C#中的空融合和右关联 - 澄清?

时间:2015-08-02 13:13:33

标签: c# null-coalescing-operator

我看过有关null-coalescing运算符的推文(右关联):

来自SPEC:

  

例如,a ?? b ?? c形式的表达式被评估为   a ?? (b ?? c)

所以还有另一个人回答说可以通过一个例子进行测试和验证:

void Main()
{
    Console.WriteLine ((P)null ?? (string)null ?? "b555");
}

public class P
{
 public static implicit operator P(string b) {throw new Exception(b??"a");}
}

结果:

Exception: b555 

但我并不了解这种行为。

问题

我已经知道??非常优先级低但仍然是:

(P)null应首先评估 (更高优先级)!

但似乎

a ?? (b ?? c)

首先评估。

为什么?

换句话说,似乎这些都是事件:

 (P)(null ?? ((string)null ?? "b555"))

然后:

(P)(null ?? "b555")

然后:

(P)"b555"

但我不明白为什么(P)适用于所有合并表达而不是null(P)null}

2 个答案:

答案 0 :(得分:3)

为什么要将隐式转化应用于null中的(P)null(P)null生成一个静态类型为P的空引用,为什么要在此处应用从字符串转换? (P)null中没有提及任何字符串。

注意编译器如何静态地键入以下表达式¹:

((string)null ?? "b555")   -> string

((P)null ?? ...some expression of type string...)    -> P

因此,

((P)null ?? (string)null ?? "b555")     -> P

现在可以按如下方式解析表达式:

  1. (P)null为空,所以我们看一下右侧。

  2. ((string)null ?? "b555")会产生字符串"b555"(不涉及P)。

  3. ((P)null ?? "b555")会产生"b555"的值。由于((P)null ?? "b555")的静态类型为Pb555会隐式转换为P,从而触发您的隐式转化。

  4. 正如预期的那样,我们得到了一个例外“b555”。

  5. PS:如果有人对对话形式的更详细解释感兴趣,我们已经将此主题与聊天和here is the transcript进行了对比。

    ¹证明:

    public static void Main()
    {
        var x = ((P)null ?? "abc");
        x.A();   // compiles
    }
    
    public class P
    {
        public static implicit operator P(string b) {throw new Exception(b??"a");}
        public void A() {}
    }
    

答案 1 :(得分:1)

(P)仅适用于第一个null。但是,类P具有从字符串到P的隐式转换,因此它抛出异常的原因。由于implicit关键字,它不需要您明确请求类型转换。