C# Null 条件运算符替代方案(条件赋值)?

C# Null Conditional Operator alternative (conditional assignment)?

C# null-conditional operator 允许有用的短路:

double? range = (unit as RangedUnit)?.WeaponRange;

不幸的是,空条件运算符不能以相同的方式用于简写赋值,因为它 returns 一个值(不能用于左手赋值):

(unit as RangedUnit)?.PreferredTarget = UnitType.Melee;

导致可能的替代语法:

if (unit is RangedUnit)
{
    (unit as RangedUnit).PreferredTarget = UnitType.Melee;
}

如果编译器知道RangedUnit是引用类型(不是值类型),为什么不能有条件地执行shorthand语法

refTypeInstance?.SomeField = value;

(即如果 refTypeInstance 为 null,则什么都不做。如果 refTypeInstance 不为 null,则执行该语句)

更新(结论):

因为他们做的事情不一样,

如果单位为空(或不是远程单位),第一个片段将 return 为空。

如果在您尝试设置某些内容时发生这种情况,那么您将无法将 null 设置为值(并且您最终会遇到错误)。

您期望的行为:

(i.e. If refTypeInstance is null, then simply do nothing. If refTypeInstance is not null, then execute the statement)

由于运营商的工作方式,这是不可能的。更具体地说,您遇到了 运算符优先级 以及如何基于此形成表达式树的问题:

在声明中

(unit as RangeUnit).PreferredTarget = UnitType.Melee;

赋值运算符(=)位于表达式树的根部,左右表达式为分支。

A NullReferenceException 会在评估左手时(赋值前)出现。此时编译器已经开始计算=。由于取消引用运算符 (.) 将在运行时抛出 NullReferenceException,编译器继续解析表达式树是安全的。

另一方面,如果允许此语句:

(unit as RangeUnit)?.PreferredTarget = UnitType.Melee;

...编译器必须发出代码来检查 refTypeInstance 的值是否为空。它可以做到这一点,但问题是,编译器将如何处理它当前正在处理的表达式树?它不能像第一个示例那样简单地继续,因为它必须丢弃表达式树上的 = 和树下的 .。它基本上必须插入两种解析树的选择,一种是 ?. 的左边是 null,另一种不是。然而,这将改变控制流,这绝对不是您对操作员的期望。

或者换句话说:当 ?. 只是将运算符的计算短路到其表达式树的分支下时,您会认为这是预期的行为。但在这种情况下,这会改变表达式树 更高层 运算符的行为,这是您绝对不会想到的。