【问题标题】:how to shorten the syntax of calling a function only if arguments aren't null in c#?仅当参数在 c# 中不为空时,如何缩短调用函数的语法?
【发布时间】:2017-09-28 15:27:13
【问题描述】:

假设我有以下代码:

var arg = getArg();
if(arg != null)
{
  foo(arg);
}

有没有办法缩短空值检查+函数调用? 例如,是否有一个可能像“安全”这样的操作符会像这样工作

foo(safe arg);

这将转化为“仅当 'arg' 不为空时才调用 foo”? 我基本上不想将可能为 null 的参数发送给函数,而是以简短的方式发送。

谢谢!

【问题讨论】:

  • 与您所描述的最接近的是,如果您正在调用 foo on arg,则可以使用空条件运算符 ?。即如果你做了arg?.foo(),那么foo 只会在arg 不为空时被调用。
  • 这是严重代码异味的标志。 getArg() 有问题,它几乎肯定应该抛出异常。好吧,修复也不迟,调用后抛出异常。 Fwiw,永远不要试图掩盖一个严重的设计问题,这会伤害并让任何阅读它的人想要修复它。
  • @Abion47 三元运算符仍然需要检查 null 和要求删除检查的问题。此外,您的第一个建议完全忽略了类的设计和语义。
  • @Abion47:“如果设计得当,函数(或方法,更确切地说,因为这是 C#)不应该关心它是否作为参数传递 null” - 不同意。传递非null 引用很可能是调用有意义的先决条件。作为void 方法,它可能会检查其参数并在参数为null 时立即返回,但非void 方法不一定这样做(因为“默认值”不一定有意义)。相反,在任何情况下都应该抛出ArgumentNullException,此时显然是调用代码的责任......
  • @Abion47:如果在null参数的情况下抛出异常,调用代码执行的事先检查合理的。抛出异常的事实意味着“除非您有非null 要传递的东西,否则不要调用此方法”。调用代码检查的意思是“如果我有arg,我需要调用它上面的方法,但如果我没有arg,什么都不应该发生。”

标签: c# function null


【解决方案1】:

就我个人而言,我认为“如果此值为null,则不要调用”应该很少出现,因此输入if 应该不是那么大的问题。也就是说……

如果您愿意设置一些扩展方法来处理各种参数列表计数,您可以这样做:

static class Extensions
{
    public static void IfNotNull<T>(Action<T> func, T arg)
        where T : class
    {
        if (arg != null)
        {
            func(arg);
        }
    }
}

那么你可以这样做:

var arg = getArg();

Extensions.IfNotNull(foo, arg);

不幸的是,编译器不会使用扩展方法语法推断委托类型来执行上述操作,这将进一步缩短语法。但是您可以使用using static ... 功能将Extensions 方法带入作用域,这样您就可以在没有类名的情况下调用,如下所示:

IfNotNull(foo, arg);

根据需要将想法扩展到其他函数签名。您只需镜像用于 ActionFunc 委托类型的模式。

还要注意,上述方法增加了委托实例分配和调用的开销。它实际上与只输入if 语句并不完全相同。在大多数情况下,它根本不会对性能产生任何影响。

如果你想避免委托开销并且你愿意为你想要这样处理的每个方法编写一个新方法,你当然可以添加那个中间方法:

void SafeFoo(ArgType arg)
{
    if (arg != null)
    {
        foo(arg);
    }
}

这对我来说似乎是一个真正的痛苦,特别是如果你没有很多地方想避开if。但它就在那里。

否则,不行。该语言提供了一些不同的快捷方式来处理 null 值,但没有任何内置的方法可以满足您对特定场景的要求。

【讨论】:

    【解决方案2】:

    简答:不,没有

    建议:

    没有复杂的代码或包含第三方库,我认为您在设计代码时必须考虑以下几点:

    • 对于要提供的参数范围,这段代码应该做什么?
    • 调用那段代码的人是否知道所述方法的可能结果?

    您可以做的第一件事就是记录方法。

    在您的示例中,getArg 似乎可以返回 null。因此,一个好的方法可能是:

    /// <summary>
    /// Describe your method here
    /// </summary>
    /// <returns>Describe what it returns</returns>
    /// <remarks>May return NULL if (explain why)</remarks>
    public TypeName getArg()
    {
        //do your code here
    }
    

    太棒了。所以,现在,无论谁打算使用 getArg() 方法,都会很好地描述该方法的作用,嘿,它甚至可以在返回时给你一个 null 实例。

    您可以对foo() 执行相同的操作。现在,如果在参数中传递了null,则尚不清楚foo() 是否应该工作。但是从您对功能的描述来看,如果是的话,它似乎会破坏应用程序。

    如果是这种情况,您可能想让foo() 抛出异常。

    所以,一个好的方法是:

    /// <summary>
    /// Describe your method here
    /// </summary>
    /// <param name="args">Describe the argument here</param>
    /// <exception cref="System.ArgumentNullException">When args is null</exception>
    public void foo(TypeName args)
    {
        if (args == null)
            throw new ArgumentNullException(nameof(args));
        //do your code here
    }
    

    我们快到了。

    现在,将所有内容联系在一起的代码...

    您从文档中知道(您):

    • args 可以是null
    • 如果argsnullfoo() 将引发异常

    而且,根据文档,您知道由于性能原因,您希望尽可能避免使用try catch

    • 鼓卷 *

    您提供的代码应该是最终代码:)

    var args = getArgs();
    if (args != null)
        foo(args);
    

    但又一次。这只是使用标准的 .net 代码。

    无论哪种方式,记录您的代码始终是可取的,提供上下文并防止由于缺乏对如何使用代码的了解而导致的错误:)

    【讨论】:

    • 预期的答案是使用三元运算符,您为什么不在答案中包含它?
    • 一点也不。问题是:“仅当 'arg' 不为空时才调用 foo”?我基本上不想将可能为 null 的参数发送给函数,而是以简短的方式发送。
    • 三元运算符不会删除对 null 的检查。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-10-28
    • 1970-01-01
    • 2016-06-27
    • 1970-01-01
    • 1970-01-01
    • 2017-09-03
    • 1970-01-01
    相关资源
    最近更新 更多