C# 中的空合并和右关联 - 说明?
Null-coalescing and right-associative in C# - clarification?
我看过一条关于 null-coalescing
运算符(右结合)的推文:
来自规范:
For example, an expression of the form a ?? b ?? c
is evaluated as
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
)
(P)
仅应用于第一个 null
。但是,class P 具有从字符串到 P 的隐式转换,因此它会抛出异常。由于 implicit
关键字,它不需要您明确请求类型转换。
为什么要将隐式转换应用于 (P)null
中的 null
? (P)null
产生静态类型为 P
的空引用,为什么要在此处应用来自字符串 的任何 转换? (P)null
.
中没有提到任何字符串
注意编译器如何静态键入以下表达式¹:
((string)null ?? "b555") -> string
((P)null ?? ...some expression of type string...) -> P
因此,
((P)null ?? (string)null ?? "b555") -> P
现在表达式可以解析如下:
(P)null
为空,所以我们看右边。
((string)null ?? "b555")
产生字符串 "b555"
(不涉及 P)。
((P)null ?? "b555")
结果为 "b555"
。由于((P)null ?? "b555")
的静态类型是P
,b555
被隐式转换为P
,触发你的隐式转换。
如预期的那样,我们得到了异常“b555”。
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() {}
}
我看过一条关于 null-coalescing
运算符(右结合)的推文:
来自规范:
For example, an expression of the form
a ?? b ?? c
is evaluated asa ?? (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
)
(P)
仅应用于第一个 null
。但是,class P 具有从字符串到 P 的隐式转换,因此它会抛出异常。由于 implicit
关键字,它不需要您明确请求类型转换。
为什么要将隐式转换应用于 (P)null
中的 null
? (P)null
产生静态类型为 P
的空引用,为什么要在此处应用来自字符串 的任何 转换? (P)null
.
注意编译器如何静态键入以下表达式¹:
((string)null ?? "b555") -> string
((P)null ?? ...some expression of type string...) -> P
因此,
((P)null ?? (string)null ?? "b555") -> P
现在表达式可以解析如下:
(P)null
为空,所以我们看右边。((string)null ?? "b555")
产生字符串"b555"
(不涉及 P)。((P)null ?? "b555")
结果为"b555"
。由于((P)null ?? "b555")
的静态类型是P
,b555
被隐式转换为P
,触发你的隐式转换。如预期的那样,我们得到了异常“b555”。
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() {}
}