rea*_*art 3 c# null operators null-coalescing-operator dereference
在包含elvis运算符(即nullsafe解引用运算符;?.)的表达式上调用扩展方法时,结果null不会按预期传递给扩展方法.实质上,它可能会导致意外的空引用异常.这是一个展示这个的程序:
class Program
{
static void Main(string[] args)
{
string nil = null;
foreach (var c in ((nil?.ToCharArray()).EmptyIfDefault())) { }; // works
foreach (var c in (nil?.ToCharArray().EmptyIfDefault())) { }; // nullref
}
}
public static class Utility
{
public static char[] EmptyIfDefault(this char[] target)
{
return target ?? new char[0];
}
}
Run Code Online (Sandbox Code Playgroud)
如果这种行为是设计的吗?注意没有?ToCharArray()和EmptyIfDefault之间.如果有,我会理解当前的行为.现在,它似乎是一个错误.(将此报告给Microsoft的正确方法是什么?)
对于那些看到相同行为的人:额外的大括号似乎阻止了它.
(顺便说一句:这是我正在使用的实际EmptyIfNull :)
public static IEnumerable<TTarget> EmptyIfNull<TTarget>(this IEnumerable<TTarget> target)
{
return target ?? Enumerable.Empty<TTarget>();
}
Run Code Online (Sandbox Code Playgroud)
编辑我只是将下面给出的答案包含在我的问题中:
这与一个常见的陷阱有关:
var txt = "I am " +
age>=18 ? "mature" : "not old" +
" enough.";
Run Code Online (Sandbox Code Playgroud)
这也被解释为
var txt = "I am " +
age >= 18
? "mature"
: ("not old" + " enough.");
Run Code Online (Sandbox Code Playgroud)
重写时,没有大括号的行为是有道理的:
foreach(var c in
nil == null
? null
: nil.ToCharArray().EmptyIfDefault()) { }; // nullref
Run Code Online (Sandbox Code Playgroud)
虽然一开始它不直观,但绝对不是一个bug.你得到的是NullReferenceException因为你试图迭代null(它在评估表达式时没有抛出异常)
我们来看看这个例子:
var t = nil?.ToCharArray().EmptyIfNull();
Run Code Online (Sandbox Code Playgroud)
以上不会调用EmptyIfNull,因为nil将null和方法链短路返回null.
也就是说,我们可以将上面的内容写成:
IEnumerable<char> t;
if (nil != null)
t = nil.ToCharArray().EmptyIfNull();
else
t = null;
Run Code Online (Sandbox Code Playgroud)
请注意,EmptyIfNull 仅在初始条件通过时执行(即,nil不为null).
现在,为什么括号修复它?
var t = (nil?.ToCharArray()).EmptyIfNull();
Run Code Online (Sandbox Code Playgroud)
这可以重写为:
IEnumerable<char> t;
IEnumerable<char> temp;
if (nil != null)
temp = nil.ToCharArray();
else
temp = null;
t = temp.EmptyIfNull();
Run Code Online (Sandbox Code Playgroud)
看到短路行为仅适用于内部表达式 - 然后我们总是调用EmptyIfNull结果.