【问题标题】:C# Null propagating operator / Conditional access expression & if blocksC# Null 传播运算符/条件访问表达式 & if 块
【发布时间】:2014-10-29 07:01:12
【问题描述】:

中的 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 传播运算符的预期用例?

【问题讨论】:

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


    【解决方案1】:

    这种方式是行不通的。您可以跳过解释并查看下面的代码:)

    如您所知,?. 运算符将在子成员为 null 时返回 null。但是如果我们尝试获取一个不可为空的成员,比如返回boolAny() 方法,会发生什么?答案是编译器将在Nullable&lt;&gt; 中“包装”一个返回值。例如,Object?.Any() 将给我们bool?(即Nullable&lt;bool&gt;),而不是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 相比似乎更自然:)

    【讨论】:

    • 所以?. 实际上并没有返回null?它返回一个Nullable?
    • @PhilipPittle 它将返回值包装在 Nullable 中,用于值和原始类型
    • 或者,有些人可能更喜欢使用空合并运算符:if (c?.Objects?.Any() ?? false) { ... }
    【解决方案2】:

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

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

    在上面的示例中,将返回 Nullable&lt;int&gt; 而不是 int。对于bool,它将返回Nullable&lt;bool&gt;

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

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

    上述行的结果将是Nullable&lt;bool&gt;/bool?。稍后您可以像这样进行比较:

    使用null-coalescing operator ??

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

    使用Nullable&lt;T&gt;.GetValueOrDefault方法

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

    使用与true的比较

    if (c?.Objects?.Any() == true)
    

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 2020-11-25
        • 2017-11-15
        • 2011-05-13
        • 2018-01-08
        • 2016-09-21
        • 1970-01-01
        • 2019-02-10
        • 2020-03-30
        • 2023-03-03
        相关资源
        最近更新 更多