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为null,则根本不执行任何操作。如果refTypeInstance不为null,则执行语句)
更新(结论):
答案 0 :(得分:4)
您期望的行为:
(即如果refTypeInstance为null,则根本不执行任何操作。如果refTypeInstance不为null,则执行语句)
由于操作员的工作方式,这是不可能的。更具体地说,您遇到了运算符优先级的问题以及如何基于以下形式创建表达式树:
声明
(unit as RangeUnit).PreferredTarget = UnitType.Melee;
赋值运算符(=
)将位于表达式树的根中,左侧和右侧表达式为分支。
评估左手时(分配前)会发生NullReferenceException
。此时编译器已经开始评估=
。由于解除引用运算符(.
)将在运行时抛出NullReferenceException
,因此编译器可以安全地继续解析表达式树。
另一方面,如果允许此声明:
(unit as RangeUnit)?.PreferredTarget = UnitType.Melee;
...编译器必须发出代码来检查refTypeInstance
的值是否为空。它可以做到这一点,但问题是,编译器对目前正在经历的表达式树做了什么?它不能像第一个例子那样简单地继续下去,因为它必须丢弃表达式树上的=
和树下的.
。它基本上必须插入两个解析树的替代方案,一个是?.
的左边是null
,另一个是?.
。然而,这将是对控制流程的改变,这肯定是不你对操作员的期望。
或者换句话说:只要<?php
define('SOME_DIR', '');
$fileName = 'file';
if (! file_exists ( SOME_DIR . $fileName.'.txt' )) {
echo "not there";
//so save normally
}
else{
$files = glob(SOME_DIR.$fileName.'_*.txt');
$counter = count($files)+1;
echo "there";
$fileName = $fileName."_" .$counter.".txt";
echo $fileName;
// save with number at the end
}
只是将运算符的评估短接到表达式树的分支,就会认为这是预期的行为。但是在这种情况下,这会改变运算符在表达式树中更高的行为,你绝对不会期望。
答案 1 :(得分:1)
因为他们没有做同样的事情,
如果unit为null(或不是范围单位),则第一个片段将返回null。
如果在您尝试设置某些内容时发生这种情况,那么您将无法将null设置为值(并且最终会出现错误)。