C#空传播操作符 有条件访问表达式& if块

问题描述 投票:22回答:3

无效传播操作符 有条件访问表达式 进来 看上去是个很方便的功能,但我很好奇它是否有助于解决检查子成员是否为空,然后在if块中调用该子成员的布尔方法的问题。 但我很好奇它是否能帮助解决检查子成员是否为空,然后在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!");
  }

Will c?.Object?.Any() 编译? 如果传播运算符短路(我想这是正确的术语)为null,那么你就会有 if (null),这是无效的。

C#团队是否会解决这个问题,还是我错过了null传播操作符的预期用例?

c# null language-features c#-6.0
3个回答
48
投票

这样是不行的。你可以直接跳过解释,看看下面的代码:)

如你所知 ?. 如果一个子成员为空,操作符将返回null。但是,如果我们试图获取一个不可空的成员,如 Any() 方法,该方法返回 bool? 答案是,编译器会将返回值 "包装 "在 Nullable<>. 例如: Object?.Any() 会给我们 bool? (也就是 Nullable<bool>),而不是 bool.

唯一不能让我们使用这个表达式的是在 if 语句是不能隐式地投给 bool. 但你可以明确地做比较,我更喜欢比较到 true 像这样。

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

感谢@DaveSexton 还有另一种方式。

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

但对我来说,相比之下 true 似乎更自然 :)


6
投票

无条件操作符将返回 null 或表达式末尾的值。对于 值类型 它将返回结果为 Nullable<T>所以,在你的情况下,它将是 Nullabe<bool>. 如果我们看一下文档中的例子,对于 即将到来的C#功能 (指定 此处)它有一个例子。

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运算符 ?

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

使用 Nullable<T>.GetValueOrDefault 方法

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

使用比较 true

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

0
投票

var x = c?.Objects?.Any() 将会给你一个可空的布尔值,就像其他人说的那样,这意味着你可以使用像这样的平等操作符。

x == true

或者你可以像这样使用null coalescing来使你的结果不可为空。

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

但是,我个人认为,3态(可空)布尔值是有代码味道的。即使这个实际上是看不见的,它的存在也应该鼓励你思考你到底想做什么,并确定可空布尔是否真的是个好办法。在这种情况下,我认为你真正想做的是这样的事情----。

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()
}
© www.soinside.com 2019 - 2024. All rights reserved.