8

??C# 中的运算符在评估时是否使用短路?

var result = myObject ?? ExpressionWithSideEffects();

myObject为非空时,ExpressionWithSideEffects()不使用的结果,而是ExpressionWithSideEffects()完全跳过?

4

3 回答 3

10

是的,确实短路了。

这是在 LinqPad 中测试的片段:

string bar = "lol";
string foo = bar ?? string.Format("{2}", 1);
foo.Dump();
bar = null;
foo = bar ?? string.Format("{2}", 1);
foo.Dump();

第一个合并工作没有抛出异常,而第二个确实抛出异常(格式字符串无效)。

于 2010-06-23T16:29:33.193 回答
7

是的,它确实。与以往一样,C# 语言规范是权威来源1

从 C# 3 规范,第 7.12 节(v3 而不是 4,因为 v4 规范涉及动态细节,这在这里并不真正相关):

表达式的类型a ?? b取决于操作数类型之间可用的隐式转换。按优先顺序,a 的类型??b 是 A0、A 或 B,其中 A 是 a 的类型,B 是 b 的类型(前提是 b 具有类型),如果 A 是可空类型,则 A0 是 A 的基础类型,否则为 A . 具体a ?? b处理如下:

  • 如果 A 不是可空类型或引用类型,则会发生编译时错误。
  • 如果 A 是可空类型并且存在从 b 到 A0 的隐式转换,则结果类型为 A0。在运行时,首先评估 a。如果 a 不为 null,则将 a 解包为类型 A0,这将成为结果。否则,b 被求值并转换为 A0 类型,这成为结果。
  • 否则,如果存在从 b 到 A 的隐式转换,则结果类型为 A。在运行时,首先评估 a。如果 a 不为空,则 a 成为结果。否则,b 被评估并转换为类型 A,这成为结果。
  • 否则,如果 b 具有 B 类型并且存在从 A0 到 B 的隐式转换,则结果类型为 B。在运行时,首先计算 a。如果 a 不为 null,则将 a 解包为 A0 类型(除非 A 和 A0 是相同类型)并转换为 B 类型,这就是结果。否则, b 被评估并成为结果。
  • 否则,a 和 b 不兼容,并出现编译时错误。

第二,第三和第四个子弹是相关的。


1关于您碰巧使用的编译器是否是真实的真实来源,有一个哲学讨论......关于一种语言的真实性是它的意图还是它目前的作用

于 2010-06-23T16:42:56.440 回答
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");
    }

这些不是最好的测试名称,但你明白了。它表明空值合并运算符按预期短路。

于 2010-06-23T16:42:37.937 回答