C# 分配布尔?哄骗
考虑以下代码:C# 分配布尔?哄骗,c#,.net,compiler-construction,nullable,C#,.net,Compiler Construction,Nullable,考虑以下代码: bool x; bool? y = null; x = y?? true; 将bool?分配给bool是编译时错误,但上述代码在编译时和运行时都成功。为什么?虽然第3条语句确保我们从不将null赋值给x,但如果y不是null,我们仍然将bool?赋值给bool,所以这应该是编译器的POV错误,不是 或者是C#编译器足够聪明,能够发现特定代码段不可能创建一种情况,将null分配给x?此表达式的类型: y ?? true 是bool,不是bool? 根据C#5规范第7.13节:
bool x;
bool? y = null;
x = y?? true;
将bool?
分配给bool
是编译时错误,但上述代码在编译时和运行时都成功。为什么?虽然第3条语句确保我们从不将null
赋值给x
,但如果y
不是null,我们仍然将bool?
赋值给bool
,所以这应该是编译器的POV错误,不是
或者是C#编译器足够聪明,能够发现特定代码段不可能创建一种情况,将
null
分配给x
?此表达式的类型:
y ?? true
是bool
,不是bool?
根据C#5规范第7.13节:
表达式的类型a??b
取决于操作数上可用的隐式转换。按照优先顺序,a??b
是A0、A或b,其中A是A的类型(前提是A有一个类型),b是b的类型(前提是b有一个类型),如果A是可为空的类型,A0是A的基础类型,或者A不是。具体来说,a??b
处理如下:
- 如果存在且不是可空类型或引用类型,则会发生编译时错误
- 如果
是动态表达式,则结果类型是动态的。在运行时,首先计算b
。如果a
不为空,a
将转换为动态,这将成为结果。否则,a
将被计算,这将成为结果b
- 否则,如果A存在并且是可空类型,并且存在从
到A0的隐式转换,则结果类型为A0。在运行时,首先计算b
。如果a
不为空,a
将展开为A0类型,这将成为结果。否则,a
将被计算并转换为A0类型,这将成为结果b
- 否则,如果存在A并且存在从
到A的隐式转换,则结果类型为A。在运行时,首先计算b
。如果A
不为空,a
将成为结果。否则,a
将被计算并转换为类型A,这将成为结果b
- 否则,如果
具有类型b并且存在从a到b的隐式转换,则结果类型为b。在运行时,首先计算b
。如果a
不为空,a
将展开为A0类型(如果a存在且可为空),并转换为B类型,这将成为结果。否则,a
将被计算并成为结果b
- 否则,
和a
不兼容,会发生编译时错误b
- A是
bool?
- A0是
bool
- B是
bool
bool
,您可以将其分配给
bool x;
bool? y = null;
x = y?? true;
y??true
是y.HasValue的语法糖吗?y、 GetValuerDefault():true
。因此,您实际上是在编译器的POV中分配一个bool
。看看生成的IL,看看C#语言特性背后发生了什么
看一看。玩它会教你很多关于语言的知识 请参阅此链接的备注部分,您可以知道原因: 可为空的类型可以包含值,也可以是未定义的。这个 运算符定义当类型为可空时要返回的默认值 分配给不可为空的类型
你知道
??操作员是干什么的吗?它的字面意思是“如果左侧为空,则使用右侧”。如果您将右侧设置为bool?
也将不起作用。@ScottChamberlain:正确,但知道左侧是否为null只需在运行时确定。所以从编译器的角度来看,这难道不是一个错误吗?@ScottChamberlain:谢谢,伙计,我现在才看到。真不敢相信我居然没抓住要点。对于我们其他人来说,我上面的断言是不正确的,所以忽略它。我把它保存在这里作为历史。这里的要点是,整个RHS(y??true
)是一个单独的表达式,它不是bool?
(请参见Jon的答案以获得解释)类型。首先y
在这里是第一位,不是吗?@MarcinJuraszek:对不起,说错了——尽管我解释得不对。编辑引用规范。难怪你是最有可能在2014年将你声誉中的“k”转换为“m”的人!谢谢你。