C#NULL条件操作员替代方案(条件分配)



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设置为值(并且最终会出现错误)。

最新更新