代码之家  ›  专栏  ›  技术社区  ›  pauldoo

是不是??``操作员使用短路?

  •  8
  • pauldoo  · 技术社区  · 14 年前

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

    var result = myObject ?? ExpressionWithSideEffects();
    

    什么时候? myObject 非空,结果为 ExpressionWithSideEffects() 不使用,但会 副作用表达 完全跳过?

    3 回复  |  直到 14 年前
        1
  •  7
  •   Jon Skeet    14 年前

    是的。与以往一样,C语言规范是最终的来源 .

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

    表达式的类型 a ?? b 取决于操作数类型之间可用的隐式转换。按照优先顺序,A的类型是什么??b是a0、a或b,其中a是a的类型,b是b的类型(前提是b有类型),a0是a的基础类型,如果a是可以为空的类型,或者a是其他类型。明确地, A?B? 被处理为 跟随:

    • 如果a不是可以为空的类型或引用类型,则为编译时错误 发生。
    • 如果a是可以为空的类型,并且存在从b到的隐式转换 a0,结果类型为a0。AT 运行时,首先计算a。如果A 不为空,a被展开为类型 a0,这就是结果。 否则,对b进行评估,并 转换为a0型,这变成 结果。
    • 否则,如果存在从B到A的隐式转换,则结果类型为 a.在运行时,首先对a进行评估。 如果a不为空,则a变为 结果。否则,对b进行评估,并 转换为类型A,这将成为 结果。
    • 否则,如果B具有类型B并且存在从a0到的隐式转换 B,结果类型为B。在运行时, 首先对a进行评估。如果A不是 空,a展开为a0类型 (除非A和A0是同一类型) 转换成B型,这个 成为结果。否则,B是 评估并成为结果。
    • 否则,A和B不兼容,会出现编译时错误。

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


    关于您使用的编译器是否是 实际的 真相的来源…语言的真谛是什么? 意味 要做的事或当前要做的事 ?

        2
  •  10
  •   Will    14 年前

    是的,它确实短路了。

    以下是要在LinqPad中测试的代码片段:

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

    第一个合并在不引发异常的情况下工作,而第二个合并在不引发异常的情况下工作(格式字符串无效)。

        3
  •  0
  •   CaffGeek    14 年前

    这就是为什么我们要进行单元测试。

        [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");
        }
    

    这些不是最好的测试名称,但你知道。结果表明,零位合并运算符按预期短路。