C#空传播运算符/条件访问表达式&如果块

时间:2014-09-04 13:38:24

标签: c# null language-features c#-6.0

来自Null propagating operator / Conditional access expression看起来非常方便。但我很好奇它是否有助于解决检查子成员是否为空的问题,然后在if块内的所述子成员上调用布尔方法:

  public class Container<int>{
       IEnumerable<int> Objects {get;set;}
  }

  public Container BuildContainer()
  { 
      var c = new Container();

      if (/* Some Random Condition */)
         c.Objects = new List<int>{1,2,4};
  }

  public void Test()
  {
      var c = BuildContainer();

      //Old way
      if ( null != c && null != c.Objects && c.Objects.Any())
         Console.Write("Container has items!");


      //C# 6 way?
      if (c?.Object?.Any())
          Console.Write("Container has items!");
  }

c?.Object?.Any()会编译吗?如果传播操作符短路(我认为这是正确的术语)为空,那么你有if (null),这是无效的。

C#团队是否会解决这个问题,或者我是否错过了null传播运营商的预期用例?

3 个答案:

答案 0 :(得分:38)

它不会以这种方式工作。您可以跳过说明并查看以下代码:)

如您所知,?.运算符将在子成员为空时返回null。但是,如果我们尝试获得一个返回Any()的非可空成员(如bool方法),会发生什么?答案是编译器将&#34; wrap&#34; Nullable<>中的返回值。例如,Object?.Any()会向我们bool?Nullable<bool>),而不是bool

唯一不允许我们在if语句中使用此表达式的是,它无法隐式转换为bool。但是您可以明确地进行比较,我更喜欢与true进行比较:

if (c?.Object?.Any() == true)
    Console.Write("Container has items!");

Thanks to @DaveSexton还有另一种方式:

if (c?.Object?.Any() ?? false)
    Console.Write("Container has items!");

但就我而言,与true的比较似乎更自然:)

答案 1 :(得分:5)

Null条件运算符将返回null或表达式结尾处的值。对于value types,它会在Nullable<T>中返回结果,因此在您的情况下,它将是Nullabe<bool>。如果我们查看文档中针对Upcoming Features in C# (指定here的示例,则会有一个示例:

int? first = customers?[0].Orders.Count();

在上面的示例中,将返回int而不是Nullable<int>。对于bool,它将返回Nullable<bool>

如果您在Visual Studio "14" CTP中尝试以下代码:

Nullable<bool> ifExist = c?.Objects?.Any();

上述行的结果为Nullable<bool> / bool?。之后您可以进行比较,如:

使用null-coalescing operator ??

 if (c?.Object?.Any() ?? false)

使用Nullable<T>.GetValueOrDefault方法

if ((c?.Objects?.Any()).GetValueOrDefault())

使用与true

的比较
if (c?.Objects?.Any() == true)

答案 2 :(得分:2)

var x = c?.Objects?.Any()将为您提供可为空的布尔值,就像其他人所说的,这意味着您可以使用像这样的相等运算符

x == true

或者您可以像这样使用空合并,以使结果不可为空

var x = c?.Objects?.Any() ?? false

但是,就我个人而言,我认为三态(可为空)布尔值是代码味道。即使该代码实际上是不可见的,它的存在也应鼓励您考虑您实际要执行的操作,并确定是否可以使用可为空的布尔值。在这种情况下,我认为您真正想做的就是这样-

var objects = c?.Objects ?? Enumerable.Empty<Object>();
if (objects.Any())
{
 ...
}

将其放在扩展方法中,它将更加简洁-

public static bool IsNullOrEmpty<T>(this IEnumerable<T> collection)
{
   return !(collection ?? Enumerable.Empty<T>()).Any()
}