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

时间:2011-06-04 16:53:25

标签: c#

  

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

的表达式      

先?第二次 - 第三次

     

评估为

     

先? (第二次 - 第三次)

根据上述规则,我认为以下翻译不正确。

发件人:

Address contact = user.ContactAddress;
if (contact == null)
{
    contact = order.ShippingAddress;
    if (contact == null)
    {
        contact = user.BillingAddress;
    }
}

Address contact = user.ContactAddress ??
                  order.ShippingAddress ??
                  user.BillingAddress;

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

Address contact = (user.ContactAddress ?? order.ShippingAddress) ??
                   user.BillingAddress;

4 个答案:

答案 0 :(得分:35)

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

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

输出:

Unbracketed:
Foo to Baz
Grouped to the left:
Foo to Bar
Foo to Bar
Bar to Baz
Grouped to the right:
Foo to Baz

换句话说,

x ?? y ?? z

的行为与

相同
x ?? (y ?? z)

相同
(x ?? y) ?? z

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

编辑:我现在有another question来涵盖双重转换...

答案 1 :(得分:24)

Jon的回答是正确的。

为了清楚起见:C#中的??运算符是右关联。我刚刚完成了二元运算符解析器并验证了解析器将??视为右关联。

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

  

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

更新:如评论中所述,lambda运算符=>也是右关联的。

答案 2 :(得分:5)

我无法看到它的重要性:

(a ?? b) ?? c

a ?? (b ?? c)

有相同的结果!

答案 3 :(得分:4)

两者都按预期工作,有效相同,因为表达式涉及简单类型(谢谢@Jon Skeet)。它将在您的示例中从左到右链接到第一个非null。

将此运算符与operators of different precedence组合时,优先级(感谢@Ben Voigt)更有趣:

value = A ?? B ? C : D ?? E;

基本上,关联性通过运算符优先级或通过用户引入的子表达式(括号)来表达。