我认为我们都同意C#6.0中引入的空条件成员访问运算符?.
非常方便。
但是我一直想知道一件事。给出以下代码:
using System.Collections.Generic;
public class MyClass
{
public void DoSomething(Foo foo)
{
var knownIndices = new[] { 42 };
bool overlaps;
// might throw a null reference exception
overlaps = foo.Indices.Overlaps(knownIndices);
// how I used to do it
overlaps = foo != null && foo.Indices != null && foo.Indices.Overlaps(knownIndices);
// with null conditional member access (won't compile)
//overlaps = foo?.Indices?.Overlaps(knownIndices).GetValueOrDefault();
// with null conditional member access (using local variable)
bool? overlapsOrIsIndeterminable = foo?.Indices?.Overlaps(knownIndices);
overlaps = overlapsOrIsIndeterminable.GetValueOrDefault();
// with null conditional member access (inlined)
overlaps = (foo?.Indices?.Overlaps(knownIndices)).GetValueOrDefault();
// with null conditional member access and null-coalescing
overlaps = foo?.Indices?.Overlaps(knownIndices) ?? false;
}
public class Foo
{
public HashSet<int> Indices;
}
}
为什么在链接表达式中必须使用括号?正如我们在示例中使用局部变量所见,?.Overlaps()
显然评估为可为空的布尔值,因此我希望.GetValueOrDefault()
是可编译的。
The C# language reference指出成员访问运算符.
和空条件成员访问运算符?.
都是主要运算符,因此共享相同的优先级。
.
尽管在语言参考中有规定,但其优先级是否高于?.
?
答案 0 :(得分:3)
是。尽管语言参考中有说明,但优先级比?。?
空条件运算符是一种特殊情况。就像Dave解释的那样,如果?.
运算符右边的任何连续表达式都不为null
,则不会对其进行求值。如果包含?.
运算符的整个表达式的结果通常将评估为原始值(例如int
),则它将实际上评估为Nullable<int>
值,但该值不适用于操作员的右侧。在运算符的右边,您可以假定该值不为null(这是空条件运算符的功效)。
虽然foo.GetIntValue()
返回int
,但是foo?.GetIntValue()
返回Nullable<int>
。如果附加到此表达式,则“目标”值的类型为int
,而不是Nullable<int>
。因此,以下代码无法编译,因为GetValueOrDefault
是Nullable<int>
的成员,而不是int
的成员。
foo?.GetIntValue().GetValueOrDefault(); // ERROR
由于 entire 表达式的计算结果为Nullable<int>
,因此添加方括号确实可以调用GetValueOrDefault
。
(foo?.GetIntValue()).GetValueOrDefault();
请注意,您可以将此操作符与null-coalescing operator
无缝组合foo?.GetIntValue() ?? 1; // If foo is null, this expression will evaluate to 1
答案 1 :(得分:2)
空条件运算符正在短路。如果条件成员访问和索引操作链中的一个操作返回null,则链中其余部分的执行将停止。在下面的示例中,如果A,B或C的值为空,则E不执行。
C#
复制 A?.B?.C?.Do(E); A?.B?.C?[E];