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

标签 c# short-circuiting null-conditional-operator

<分区>

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

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 为空,则什么也不做。如果 refTypeInstance 不为空,则执行该语句)

更新(结论):

  • 空条件运算符不能用在赋值语句的左侧,因为这会违反赋值语句表达式树的预期求值逻辑(短路赋值操作而不执行它)
  • 理想的解决方案是一个新的条件赋值运算符(仅当赋值的左侧不为空时才执行),本质上是“如果不为空,一个赋值一个衬里”

最佳答案

您期望的行为:

(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;

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

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

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

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

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

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

关于C# Null 条件运算符替代方案(条件赋值)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41118670/

相关文章:

python - Python 在短路 bool 值之前会引发 TypeErrors 吗?

c++ - 如何使 `short-circuit evaluation` 在 `fold expressions` 中也可用?

Python bool 运算符的优先级规则

c# - UnassignedReferenceException 即使使用 null 条件运算符

c# - 在 C# 中使用 XSLT 转换 XML

c# - 预测周期性时间序列的趋势线

c# - 这是否违反了开闭原则?

C# - 使用 SSL 保护 `sockets`

c# - 空条件运算符对委托(delegate)和常规对象的功能是否相同?

c# - 调用方法时处理空对象