c#null-条件运算符允许有用的短路:
double? range = (unit as RangedUnit)?.WeaponRange;
不幸的是,无效的运算符不能以相同的方式用于短手分配,因为它返回一个值(不能在左手分配中使用):
(unit as RangedUnit)?.PreferredTarget = UnitType.Melee;
导致可能的替代语法:
if (unit is RangedUnit)
{
(unit as RangedUnit).PreferredTarget = UnitType.Melee;
}
如果编译器知道rangedunit是一种参考类型(不是值类型),为什么它不能有条件执行速记语法
refTypeInstance?.SomeField = value;
(即,如果reftypeinstance为null,那么简单地做任何事情。如果reftypeinstance不是null,则执行语句)
)更新(结论):
- 无效的操作员不能在作业语句的左侧使用,因为这将违反分配语句的表达树的预期评估逻辑(简短的循环分配操作而根本不执行)
- 理想的解决方案是一个新的条件分配运算符(仅当作业的左侧不是null时执行)
您期望的行为:
(即,如果reftypeinstance为null,那么简单地做任何事情。如果reftypeinstance不是null,则执行语句)
)
由于运营商的工作方式是不可能的。更具体地说,您遇到操作员优先的问题,以及如何根据以下方式形成表达式树:
在语句中
(unit as RangeUnit).PreferredTarget = UnitType.Melee;
分配操作员(=
)将在表达树的根部,左表和右表达式为分支。
评估左手(分配之前)时,将发生NullReferenceException
。此时,编译器已经开始评估=
。由于取消运算符(.
)将在运行时投掷NullReferenceException
,因此编译器可以继续解析表达式树是安全的。
另一方面,如果允许此语句:
(unit as RangeUnit)?.PreferredTarget = UnitType.Melee;
...编译器必须发出代码以检查refTypeInstance
的值是否为null。它可以做到这一点,但是问题是,编译器对当前正在经历的表达树有什么作用?它不能像第一个示例一样简单地进行,因为它必须将=
丢弃在表达树和.
下方。基本上,它必须插入两个解析树的替代方法,一个?.
的左侧是null
,而一个是当它不是。但是,这将是控制流的改变,这绝对是不是您对操作员的期望。
或以不同的方式提出:长期以来,只要 ?.
便在表达树的分支上对操作员的评估进行简短评估时,您会认为这是一种预期的行为。但是在这种情况下,这将改变表达树中运算符上升的行为,您绝对不会期望。
因为他们没有做同样的事情,
如果单元为null(或不是远程单元),则第一个片段将返回null。
如果您试图设置某些东西,那么您将无法将null设置为值(并且最终会出现错误)。