null合并运算符的右关联如何表现?

q09*_*987 29 c#

null coalescing运算符是右关联的,表示表单的表达式

第一个?第二个 - 第三个

被评估为

第一个?(第二次 - 第三次)

基于上述规则,我认为以下翻译是不正确的.

从:

Address contact = user.ContactAddress;
if (contact == null)
{
    contact = order.ShippingAddress;
    if (contact == null)
    {
        contact = user.BillingAddress;
    }
}
Run Code Online (Sandbox Code Playgroud)

至:

Address contact = user.ContactAddress ??
                  order.ShippingAddress ??
                  user.BillingAddress;
Run Code Online (Sandbox Code Playgroud)

相反,我认为以下是正确的(如果我错了请纠正我)

Address contact = (user.ContactAddress ?? order.ShippingAddress) ??
                   user.BillingAddress;
Run Code Online (Sandbox Code Playgroud)

Jon*_*eet 36

这个规范实际上是自相矛盾的.

C#4规范第7.13节规定:

空合并运算符是右关联运算符,这意味着操作从右到左分组.例如,表单的表达式a ?? b ?? c被评估为a ?? (b ?? c).

另一方面,正如已经指出的那样,7.3.1声称:

除赋值运算符外,所有二元运算符都是左关联运算符

我完全同意,对于简单的情况,你如何进行分组并不重要......但是如果操作数具有不同的类型,可能存在由于隐式类型转换做有趣的事情而真正重要的情况.

我会进一步考虑,ping Mads和Eric,并为深度C#的相关部分添加一个错误(这启发了这个问题).

编辑:好的,我现在有一个例子,它确实很重要...并且空合并运算符肯定是正确的 -至少在MS C#4编译器中.码:

using System;

public struct Foo
{
    public static implicit operator Bar(Foo input)
    {
        Console.WriteLine("Foo to Bar");
        return new Bar();
    }

    public static implicit operator Baz(Foo input)
    {
        Console.WriteLine("Foo to Baz");
        return new Baz();
    }
}

public struct Bar
{
    public static implicit operator Baz(Bar input)
    {
        Console.WriteLine("Bar to Baz");
        return new Baz();
    }
}

public struct Baz
{
}


class Test
{
    static void Main()
    {
        Foo? x = new Foo();
        Bar? y = new Bar();
        Baz? z = new Baz();

        Console.WriteLine("Unbracketed:");
        Baz? a = x ?? y ?? z;
        Console.WriteLine("Grouped to the left:");
        Baz? b = (x ?? y) ?? z;
        Console.WriteLine("Grouped to the right:");
        Baz? c = x ?? (y ?? z);
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

Unbracketed:
Foo to Baz
Grouped to the left:
Foo to Bar
Foo to Bar
Bar to Baz
Grouped to the right:
Foo to Baz
Run Code Online (Sandbox Code Playgroud)

换一种说法,

x ?? y ?? z
Run Code Online (Sandbox Code Playgroud)

行为与...相同

x ?? (y ?? z)
Run Code Online (Sandbox Code Playgroud)

一样

(x ?? y) ?? z
Run Code Online (Sandbox Code Playgroud)

我目前还不确定为什么在使用时有两次从Foo到Bar的转换(x ?? y) ?? z- 我需要仔细检查一下...

编辑:我现在有另一个问题来涵盖双重转换......

  • 好的,没有用户定义的转换,测试会更简单。假设您有一个动物类,其中包含派生类“猫”和“狗”。然后假设您有三个变量“ animal”,“ cat”和“ dog”,每个变量都有明显的编译时类型。然后用`(动物??猫)?? 狗`将找到一种良好的通用基础类型,而“动物” (cat ?? dog)`不会编译,因为猫不是狗,而狗不是猫。因此,要测试`??`的关联性,您只需要查看**`animal ??即可。猫 ??dog **(不带括号)是否编译。 (3认同)

Eri*_*ert 24

乔恩的回答是正确的.

需要明确的是:??C#中的运算符是右关联的.我刚刚完成了二元运算符解析器并验证了解析器将其??视为右关联.

正如Jon指出的那样,规范说??运算符是右关联的,并且除了赋值之外的所有二元运算符都是左关联的.由于规范自相矛盾,显然其中只有一个是正确的.我将修改规范,说:

除了简单赋值,复合赋值和空合并运算符之外,所有二元运算符都是左关联的


Ben*_*igt 5

我无法看出它的重要性,两者:

(a ?? b) ?? c
Run Code Online (Sandbox Code Playgroud)

a ?? (b ?? c)
Run Code Online (Sandbox Code Playgroud)

有相同的结果!

  • 当 `a`、`b` 和 `c` 的类型相同时,它们会这样做。但是假设类型是 A、B 和 C,并且存在从 A 到 B、A 到 C 和 B 到 C 的隐式转换……那么会发生什么?看我的回答:) (2认同)