Answers:
它是空条件运算符。它基本上意味着:
“评估第一个操作数;如果为空,则停止,结果为空。否则,评估第二个操作数(作为第一个操作数的成员访问)。”
在您的示例中,关键是如果a
is null
,a?.PropertyOfA
则将求值null
而不是抛出异常-然后它将与该null
引用进行比较foo
(使用字符串的==
重载),发现它们不相等,执行将进入if
语句主体。
换句话说,它是这样的:
string bar = (a == null ? null : a.PropertyOfA);
if (bar != foo)
{
...
}
...除了a
只评估一次。
请注意,这也可以更改表达式的类型。例如,考虑FileInfo.Length
。那是type的属性long
,但是如果将其与null条件运算符一起使用,则最终会得到type的表达式long?
:
FileInfo fi = ...; // fi could be null
long? length = fi?.Length; // If fi is null, length will be null
展平层次结构和/或映射对象时,它非常有用。代替:
if (Model.Model2 == null
|| Model.Model2.Model3 == null
|| Model.Model2.Model3.Model4 == null
|| Model.Model2.Model3.Model4.Name == null)
{
mapped.Name = "N/A"
}
else
{
mapped.Name = Model.Model2.Model3.Model4.Name;
}
可以这样写(与上面的逻辑相同)
mapped.Name = Model.Model2?.Model3?.Model4?.Name ?? "N/A";
(??或null推算运算符不同于?或null条件运算符)。
也可以将其与Action一起用于赋值运算符。代替
Action<TValue> myAction = null;
if (myAction != null)
{
myAction(TValue);
}
可以简化为:
myAction?.Invoke(TValue);
使用系统;
public class Program
{
public static void Main()
{
Action<string> consoleWrite = null;
consoleWrite?.Invoke("Test 1");
consoleWrite = (s) => Console.WriteLine(s);
consoleWrite?.Invoke("Test 2");
}
}
结果:
测试2
|| Model.Model2.Model3.Model4.Name == null
具有相同的逻辑,否则情况Model.Model2.Model3.Model4.Name
是null
,mapped.Name
将留null
Model.Model2.Model3.Model4.Name
是,请尝试查看两种情况下会发生什么null
。
else
-branch并拥有mapped.Name = Model.Model2.Model3.Model4.Name -> mapped.Name = null
,而第二个示例将替换为mapped.Name = "N/A"
。参见编辑过的DotNetFiddle
这对于C#来说是相对较新的,这使我们可以轻松地在方法链中针对null或非null值调用函数。
实现相同目的的旧方法是:
var functionCaller = this.member;
if (functionCaller!= null)
functionCaller.someFunction(var someParam);
现在,通过以下操作,它变得更加容易:
member?.someFunction(var someParam);
我强烈建议您在这里阅读: