来自Null propagating operator / Conditional access expression的c#-6.0看起来非常方便。但我很好奇它是否有助于解决检查子成员是否为空的问题,然后在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传播运营商的预期用例?
答案 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?
。之后您可以进行比较,如:
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()
}