``??`` 运算符是否使用短路?

发布于 2024-09-07 10:41:12 字数 258 浏览 3 评论 0原文

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

var result = myObject ?? ExpressionWithSideEffects();

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

Does the ?? operator in C# use shortcircuiting when evaluating?

var result = myObject ?? ExpressionWithSideEffects();

When myObject is non-null, the result of ExpressionWithSideEffects() is not used, but will ExpressionWithSideEffects() be skipped completely?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

情何以堪。 2024-09-14 10:41:12

是的,确实会短路。

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

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

第一个合并工作时不会引发异常,而第二个合并会引发异常(格式字符串无效)。

Yes, it does short circuit.

Here's a snippet to test in LinqPad:

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

The first coalesce works without throwing an exception while the second one does throw (the format string is invalid).

谎言 2024-09-14 10:41:12

是的,确实如此。一如既往,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 不是可为 null 的类型或引用类型,则会出现编译时错误
    发生。
  • 如果 A 是可以为 null 的类型,并且存在从 b 到
    A0,结果类型为A0。在
    运行时,a 首先被评估。如果一个
    不为空,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 关于您碰巧使用的编译器是否是实际真相来源,需要进行一场哲学讨论...某种语言的真相是什么 >打算做什么或者它目前做什么

Yes it does. As ever, the C# language specification is the definitive source1.

From the C# 3 spec, section 7.12 (v3 rather than 4, as the v4 spec goes into dynamic details which aren't really relevant here):

The type of the expression a ?? b depends on which implicit conversions are available between the types of the operands. In order of preference, the type of a ?? b is A0, A, or B, where A is the type of a, B is the type of b (provided that b has a type), and A0 is the underlying type of A if A is a nullable type, or A otherwise. Specifically, a ?? b is processed as
follows:

  • If A is not a nullable type or a reference type, a compile-time error
    occurs.
  • If A is a nullable type and an implicit conversion exists from b to
    A0, the result type is A0. At
    run-time, a is first evaluated. If a
    is not null, a is unwrapped to type
    A0, and this becomes the result.
    Otherwise, b is evaluated and
    converted to type A0, and this becomes
    the result.
  • Otherwise, if an implicit conversion exists from b to A, the result type is
    A. At run-time, a is first evaluated.
    If a is not null, a becomes the
    result. Otherwise, b is evaluated and
    converted to type A, and this becomes
    the result.
  • Otherwise, if b has a type B and an implicit conversion exists from A0 to
    B, the result type is B. At run-time,
    a is first evaluated. If a is not
    null, a is unwrapped to type A0
    (unless A and A0 are the same type)
    and converted to type B, and this
    becomes the result. Otherwise, b is
    evaluated and becomes the result.
  • Otherwise, a and b are incompatible, and a compile-time error occurs.

The second, third and fourth bullets are the relevant ones.


1 There's a philosophical discussion to be had about whether the compiler you happen to be using is the actual source of truth... is the truth about a language what it's meant to do or what it currently does?

瞳孔里扚悲伤 2024-09-14 10:41:12

这就是我们进行单元测试的原因。

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

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

This is why we have unit testing.

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

These aren't the best test names, but you get the idea. It shows that the null coalesce operator short circuits as expected.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文