首页 文章

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

提问于
浏览
28

null coalescing运算符是右关联的,这意味着表单的第一个表达式?第二个 - 第三个被评估为第一个? (第二次 - 第三次)

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

From:

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

To:

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

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

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

4 回答

  • 33

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

    C#4规范第7.13节规定:

    null合并运算符是右关联运算符,这意味着操作从右到左分组 . 例如,一个表达式为?? ?? b ?? c被评估为?? (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
    

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

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

  • 5

    乔恩的回答是正确的 .

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

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

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

  • 4

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

    (a ?? b) ?? c
    

    a ?? (b ?? c)
    

    有相同的结果!

  • 22

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

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

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

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

相关问题