我发现了我的程序的一个奇怪的行为,经过进一步的分析,我发现在我的C#知识或其他地方可能存在错误 . 我相信这是我的错,但我无法在任何地方找到答案......
public class B
{
public static implicit operator B(A values)
{
return null;
}
}
public class A { }
public class Program
{
static void Main(string[] args)
{
A a = new A();
B b = a ?? new B();
//b = null ... is it wrong that I expect b to be B() ?
}
}
此代码中的变量“b”被计算为null . 我不明白为什么它是null .
我用Google搜索并在此问题中找到了回复 - Implicit casting of Null-Coalescing operator result - 与官方规范一致 .
但是按照这个规范,我找不到“b”为空的原因:(也许我读错了,在这种情况下我为垃圾邮件道歉 .
如果A存在且不是可空类型或引用类型,则发生编译时错误 .
......事实并非如此 .
如果b是动态表达式,则结果类型是动态的 . 在运行时,首先评估a . 如果a不为null,则a将转换为dynamic,这将成为结果 . 否则,评估b,结果成为结果 .
......事实并非如此 .
否则,如果A存在并且是可空类型,并且从b到A0存在隐式转换,则结果类型为A0 . 在运行时,首先评估a . 如果a不为null,则打开a以键入A0,这将成为结果 . 否则,b被评估并转换为类型A0,这就成了结果 .
...存在,从b到A0的隐式转换不存在 .
否则,如果A存在且从b到A存在隐式转换,则结果类型为A.在运行时,首先计算a . 如果a不为null,则a成为结果 . 否则,b被评估并转换为类型A,这就是结果 .
...存在,从b到A的隐式转换不存在 .
否则,如果b具有类型B并且从a到B存在隐式转换,则结果类型为B.在运行时,首先计算a . 如果a不为null,则打开a以键入A0(如果A存在且可为空)并转换为类型B,这将成为结果 . 否则,b被评估并成为结果 .
... b具有类型B,并且从a到B存在隐式转换.a被评估为null . 因此,应评估b,结果应为b .
否则,a和b不兼容,并发生编译时错误 . 不会发生
我错过了什么吗?
4 回答
那么,规范说(我改为
x
和y
,以减少混淆):有时候是这样的 . 首先,检查左侧
x
(仅为a
)null
. 但它本身并不是null
. 然后左侧 is 被使用 . 然后运行隐式转换 . 其类型B
的结果是......null
.请注意,这与以下内容不同:
在这种情况下,左操作数是一个表达式(
x
),其本身是null
,结果变为右侧(y
) .也许引用类型之间的隐式转换应该返回
null
(if和)仅当原始是null
时,这是一个好习惯吗?我想那些编写规范的人可能会这样做(但没有):
也许那会更直观?无论转换的输入是否为
null
,它都会强制运行时调用隐式转换 . 如果典型的实现快速确定null → null
,那应该不会太昂贵 .为什么期望null-coalescing运算符返回
new B()
?a
不为空,因此a ?? new B()
的计算结果为a
.既然我们知道将返回
a
,我们需要确定结果的类型(T
)以及是否需要将a
转换为T
.从
A
到B
存在隐式转换,因此B
是表达式的结果类型 . 这意味着a
将隐式投放到B
. 你的隐式运算符返回null
.实际上,如果您编写
var b = a ?? new B();
(注意var
),您将看到编译器推断B
是表达式返回的类型 .你在解释这个错误 . 没有什么说在执行
null
检查之前完成了a
到B
转换 . 它声明null
检查完成 before 转换!你的情况适合那个:
我们需要看的部分是null-coalescing表达式的编译时类型 .
把它变成伪代码: