该 无效传播操作符 有条件访问表达式 进来 c#-6.0 看上去是个很方便的功能,但我很好奇它是否有助于解决检查子成员是否为空,然后在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传播操作符的预期用例?
这样是不行的。你可以直接跳过解释,看看下面的代码:)
如你所知 ?.
如果一个子成员为空,操作符将返回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
似乎更自然 :)
无条件操作符将返回 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?
. 以后你就可以做这样的比较了。
if (c?.Object?.Any() ?? false)
使用 Nullable<T>.GetValueOrDefault
方法
if ((c?.Objects?.Any()).GetValueOrDefault())
使用比较 true
if (c?.Objects?.Any() == true)
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()
}