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

时间:2012-06-29 19:04:42

标签: c# syntax

这里的基本问题 - 我有许多代码行看起来像:

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

此功能中类似的行重复了很多。 long_expression每次都不同。我试图找到避免重复long_expression但保持此紧凑的方法。与operator ??相反的东西。目前我正在考虑放弃并将其放在多行上,如:

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

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

7 个答案:

答案 0 :(得分: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);
}

然后:

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

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

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

其中Foosome_long_expression的类型。

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

答案 1 :(得分:49)

我发现this answer很有见地。

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

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

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

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

答案 2 :(得分: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);

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

答案 3 :(得分:5)

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

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

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

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

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

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

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

Anders,进行此类更改永远不会太晚,并添加一个编译器开关来启用它们!

答案 4 :(得分:1)

您可以为long_expression评估为的任何类型编写扩展方法:

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

这可以在任何MyType引用上调用,即使该引用为null

答案 5 :(得分:0)

您可以将long_expression == null放入具有短名称的函数中,并且每次都调用该函数。

答案 6 :(得分:0)

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