null合并运算符的右关联的行为

本文关键字:关联 运算符 null 合并 | 更新日期: 2023-09-27 17:58:34

空合并运算符是右关联的,这意味着形式的表达式

首先??第二第三个

被评估为

首先??(第二??第三)

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

发件人:

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;

null合并运算符的右关联的行为

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

C#4规范第7.13节规定:

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

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

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

我完全同意,对于简单的情况,如何分组并不重要。。。但在的情况下,如果操作数具有不同的类型,则由于隐式类型转换会做一些有趣的事情,因此它可能真的很重要。

我将进一步考虑,ping Mads和Eric,并为C#的相关部分添加一个勘误表(这激发了这个问题)。

编辑:好吧,我现在有一个例子,确实很重要。。。并且空合并运算符肯定是right-关联的,至少在MSC#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的转换-我需要更仔细地检查。。。

编辑:我现在有另一个问题要讨论双重转换。。。

Jon的回答是正确的。

需要明确的是:C#中的??运算符是右关联。我刚刚浏览了二进制运算符解析器,并验证了解析器将??视为正确的关联。

正如Jon所指出的,规范指出??运算符是右关联的,并且除赋值之外的所有二进制运算符都是左关联的。由于规范本身矛盾,显然只有其中一个是正确的。我会修改规范,说这样的话:

除了简单赋值、复合赋值和零合并运算符外,所有二进制运算符都是左关联

UPDATE:如注释中所述,lambda运算符=>也是右关联的。

我看不出它有多重要,两者都是:

(a ?? b) ?? c

a ?? (b ?? c)

有同样的结果!

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

当将此运算符与不同优先级的运算符组合时,优先级(感谢@Ben Voigt)更有趣:

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

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