a =(x == null)的最佳语法?null:x.func()

ten*_*our 58 c# syntax

这里的基本问题 - 我有许多代码行,如下所示:

var a = (long_expression == null) ? null : long_expression.Method();
Run Code Online (Sandbox Code Playgroud)

类似的行在这个函数中重复了很多.long_expression每次都不一样.我试图找到一种方法来避免重复long_expression,但保持这种紧凑.像是相反的东西operator ??.目前我正在考虑放弃并将其放在多行上,如:

var temp = long_expression;
var a = (temp == null) ? null : temp.Method();
Run Code Online (Sandbox Code Playgroud)

但我很好奇是否有一些我不知道的聪明语法会使这更加简洁.

Jon*_*eet 77

好吧,你可以使用这样的扩展方法:

public static TResult NullOr<TSource, TResult>(this TSource source,
    Func<TSource, TResult> func) where TSource : class where TResult : class
{
    return source == null ? null : func(source);
}
Run Code Online (Sandbox Code Playgroud)

然后:

var a = some_long_expression.NullOr(x => x.Method());
Run Code Online (Sandbox Code Playgroud)

或者(取决于您的C#版本)

var a = some_long_expression.NullOr(Foo.Method);
Run Code Online (Sandbox Code Playgroud)

在哪里Foo的类型some_long_expression.

我不认为我做到这一点,虽然.我只是使用两行版本.它更简单,更不聪明 - 虽然"聪明"对于Stack Overflow来说很有趣,但对于真正的代码来说通常不是一个好主意.

  • +1代表"我只使用两行版本." (11认同)
  • 我一直不喜欢在null引用上运行的扩展方法.在null上调用方法应该IMO总是抛出一个空引用异常.我知道扩展方法实际上是静态辅助方法,但对于代码的读者来说并不总是清楚. (4认同)

Amy*_*y B 49

我发现这个答案很有见地.

通过执行此分配,您可以将null更深入地传播到系统中.您将不得不再次(以及反复)编写空处理条件来处理这些传播.

不是允许执行继续使用空值,而是使用更好的表示替换null(从链接引用)

  1. 如果null表示空集合,请使用空集合.
  2. 如果null表示异常情况,则抛出异常.
  3. 如果null表示意外未初始化的值,则显式初始化它.
  4. 如果null表示合法值,则测试它 - 或者甚至更好地使用执行null操作的NullObject.

特别是,用空集合替换空集合引用已经为我节省了许多空测试.


Poi*_*ars 5

var x = "";

/* try null instead */
string long_expression = "foo";

var a = ((x = long_expression) == null) ? null : x.ToUpper();

/* writes "FOO" (or nothing) followed by newline */
Console.WriteLine(a);
Run Code Online (Sandbox Code Playgroud)

初始化值x的类型必须与long_expression(此处:)的类型兼容string.使用Mono C#编译器,版本2.10.8.1(来自Debian软件包mono-gmcs = 2.10.8.1-4).


Ken*_*ett 5

我认为C#语言真的可以使用一个新的运算符来实现这种逻辑 - 它很常见,运算符可以简化无数代码行.

我们需要的东西是"??" 或"如果为null然后"运算符,但它作为特殊''.具有"if not null"条件的点运算符.为了第一 '?' 就像"?:"if-then,第二个'?'的'if'部分 对于可空类型,表示'null'.我想我们需要一个".?" 运算符与'.'一样工作,除非它只是在左表达式为null而不是抛出异常时求值为null.我想这将是一个"dot not null"操作符(好吧,所以也许".!?"会更合乎逻辑,但是不要去那里).

所以,你这么常见的例子可能会丢失这样的冗余符号名称:

var a = long_expression.?Method();
Run Code Online (Sandbox Code Playgroud)

有大量的C#代码有嵌套的空值检查,这将大大受益.试想,如果这样做会有多好:

if (localObject != null)
{
    if (localObject.ChildObject != null)
    {
        if (localObject.ChildObject.ChildObject != null)
            localObject.ChildObject.ChildObject.DoSomething();
    }
}
Run Code Online (Sandbox Code Playgroud)

可能只是:

localObject.?ChildObject.?ChildObject.?DoSomething();
Run Code Online (Sandbox Code Playgroud)

还有大量的代码,其中应该存在的空检查丢失,导致偶尔的运行时错误.所以,实际上使用新的'.?' 默认情况下,运营商会消除这些问题......我们无法扭转"."的行为,这可能是不幸的.和'.?' 在这一点上,所以只有新的'.?' 如果左侧为空,则抛出异常 - 这将是更清晰,更合乎逻辑的方式,但是破坏更改非常糟糕.虽然,有人可能会说这个特定的更改可能会解决许多隐藏的问题,并且不太可能破坏任何东西(只有代码需要抛出空引用异常).哦,嗯......一个人总能做梦......

检查null的唯一缺点就是轻微的性能损失,这绝对是为什么''.不检查null.但是,我真的认为能够使用'.?' 当你关心表现(并且知道左侧永远不会为空)时,这将是更好的方法.

在类似的说明中,对'foreach'进行检查并忽略null集合也会更好.不再需要用"if(collection!= null)"包装大多数"foreach"语句,或者更糟糕的是,养成总是使用空集合而不是null的常见习惯......在某些情况下这很好,但更糟糕的是性能问题比null检查在复杂的对象树中完成,其中大多数集合是空的(我已经看过很多).我认为没有'foreach'检查null以提供更好的性能的好意图在大多数情况下都适得其反.

Anders,做出这样的改变永远不会太晚,并添加一个编译器开关来启用它们!