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

基本的问题在这里 – 我有很多代码行如下所示:

var a = (long_expression == null) ? null : long_expression.Method(); 

类似的行在这个函数中重复了很多。 long_expression都是不同的。 我试图find一种方法来避免重复long_expression ,但保持这个紧凑 。 就像operator ??的对面operator ?? 。 目前我正在考虑放弃,并把它放在多行上,如:

 var temp = long_expression; var a = (temp == null) ? null : temp.Method(); 

但我很好奇,如果有一些我不知道的巧妙的语法会使这个更简洁。

那么,你可以使用这样的扩展方法:

 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); } 

然后:

 var a = some_long_expression.NullOr(x => x.Method()); 

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

 var a = some_long_expression.NullOr(Foo.Method); 

其中Foosome_long_expression的types。

我不认为我会这样做。 我只是使用两行版本。 它更简单,更不聪明 – 虽然“巧妙”是堆栈溢出的乐趣,但它通常不是一个真正的代码的好主意。

我发现这个答案有见地。

通过这样的分配,你可以更深地传播null到系统中。 你将不得不再次编写你的空处理条件(并一次又一次)来处理这些传播。

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

  1. 如果null表示一个空集合,则使用一个空集合。
  2. 如果null表示一个特例,则抛出一个Exception。
  3. 如果null表示意外未初始化的值,则显式初始化它。
  4. 如果null表示合法值,则testing它 – 或者甚至更好地使用执行空操作的NullObject。

特别是,用空集合replace空集合引用为我节省了许多空testing。

 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); 

x的初始化值的types必须与long_expression的types(这里是: string )兼容。 适用于Mono C#编译器,版本2.10.8.1(来自Debian package mono-gmcs = 2.10.8.1-4)。

我认为C#语言真的可以为这种逻辑使用一个新的运算符 – 这是相当普遍的,一个运算符会简化无数的代码行。

我们需要沿着“??” 或者“如果是空的话”操作符,但是这个操作符是特殊的。 使用“if not null”条件的点运算符。 为了第一 '?' 就像“如果”的“如果”部分,然后是第二个“?”。 代表“空”像可空types。 我觉得我们需要一个“?” 这个运算符就像“。”一样工作,只是如果左expression式为空而不是抛出exception,那么它的计算结果为空。 我想这将是一个“点不为空”的运算符(好吧,所以也许“!!?”会更合乎逻辑,但我们不要去那里)。

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

 var a = long_expression.?Method(); 

有大量的C#代码与嵌套的空检查,将大大受益。 只要想一想,如果这样做会有多好:

 if (localObject != null) { if (localObject.ChildObject != null) { if (localObject.ChildObject.ChildObject != null) localObject.ChildObject.ChildObject.DoSomething(); } } 

可能只是:

 localObject.?ChildObject.?ChildObject.?DoSomething(); 

还有一大堆的代码应该在那里失效,导致偶然的运行时错误。 所以,实际上使用新的“?” 运营商默认会消除这样的问题……也许不幸的是,我们不能扭转“'的行为。 和'?' 在这一点上,所以只有新的“。” 如果左侧为空,则抛出exception – 这将是更清洁和更合乎逻辑的方式,但是破坏性更改非常糟糕。 虽然,有人可能会认为,这种特殊的变化可能会解决很多隐藏的问题,并且不会破坏任何东西(只有那些期望引发null refexception的代码)。 噢,一个人总是可以梦想…

检查无效的唯一缺点就是轻微的性能下降,这确实是为什么“。 不检查null。 但是,我真的认为能够使用'。?' 当你关心performance(并且知道左边将永远不会是空的)将是更好的方式去。

在类似的说明中,有'foreach'检查和忽略空集合也会更好。 不再需要用“if(collection!= null)”来包装大部分'foreach'语句,或者更糟的是,养成总是使用空集合而不是空集合的习惯……在某些情况下是好的,但更糟性能问题比空检查,当这是在复杂的对象树,其中大部分集合是空的(我已经看到很多)完成。 我认为在大多数情况下,没有“foreach”检查null以提供更好的性能的好意思已经不起作用。

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

你可以为任何long_expressiontypes的值计算扩展方法:

 public static object DoMethod(this MyType pLongExpression) { return pLongExpression == null ? null : pLongExpression.Method(); } 

这将在任何MyType引用上被调用,即使这个引用是null

你可以把long_expression == null放到一个名字短的函数中,每次调用这个函数。

if(!String.IsNullOrEmpty(x))x.func()