C#中的??
运算符在评估时是否使用短路?
var result = myObject ?? ExpressionWithSideEffects();
当myObject
非空时,ExpressionWithSideEffects()
的结果未被使用,但ExpressionWithSideEffects()
会被完全跳过吗?
答案 0 :(得分:10)
是的,它会短路。
这是在LinqPad中测试的片段:
string bar = "lol";
string foo = bar ?? string.Format("{2}", 1);
foo.Dump();
bar = null;
foo = bar ?? string.Format("{2}", 1);
foo.Dump();
第一个coalesce在没有抛出异常的情况下工作,而第二个抛出则抛出(格式字符串无效)。
答案 1 :(得分:7)
是的。与以往一样,C#语言规范是权威来源 1 。
从C#3规范,第7.12节(v3而不是4,因为v4规范进入动态细节,这里没有真正相关):
表达式
a ?? b
的类型取决于操作数类型之间可用的隐式转换。按优先顺序排列,类型为?? b是A0,A或B,其中A是a的类型,B是b的类型(假设b具有类型),如果A是可空类型,则A0是A的基础类型,否则A 。具体而言,a ?? b
被处理为 如下:
- 如果A不是可空类型或引用类型,则为编译时错误 发生。
- 如果A是可空类型,则从b到存在隐式转换 A0,结果类型为A0。在 运行时,首先评估a。如果一个 不是null,a是打开的类型 A0,这就是结果。 否则,b被评估并且 转换为A0型,这就变成了 结果。
- 否则,如果从b到A存在隐式转换,则结果类型为 A.在运行时,首先评估a。 如果a不为null,则a成为 结果。否则,b被评估并且 转换为A型,这就变成了 结果。
- 否则,如果b具有类型B并且存在从A0到A0的隐式转换 B,结果类型为B.在运行时, 首先评估a。如果不是 null,a被解包为A0类型 (除非A和A0是相同的类型) 并转换为B型,这个 成为结果。否则,b是 评估并成为结果。
- 否则,a和b不兼容,并发生编译时错误。
第二,第三和第四发子弹是相关的。
1 关于你碰巧使用的编译器是否是实际的真实来源 - 还有一个哲学讨论......关于语言的真相是什么是意味着要做什么或者当前做什么?
答案 2 :(得分:0)
这就是我们进行单元测试的原因。
[TestMethod]
public void ShortCircuitNullCoalesceTest()
{
const string foo = "foo";
var result = foo ?? Bar();
Assert.AreEqual(result, foo);
}
[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void ShortCircuitNullCoalesceFails()
{
const string foo = null;
var result = foo ?? Bar();
}
private static string Bar()
{
throw new ArgumentException("Bar was called");
}
这些不是最好的测试名称,但你明白了。它显示空合并运算符如预期的那样短路。