可空类型为什么可以被赋值为 null?

3
我们知道可以将null赋值给可空类型。例如:
Nullable<Int32> x = 2021;
Nullable<Int32> y = null;

我们知道第二个语句是可行的,因为我们被告知它是可行的,我们只接受了它,没有问为什么。但如果你看一下Nullable<T>的源代码是这样的:
public struct Nullable<T> where T : struct {
   ...
   public static implicit operator Nullable<T>(T value) {
      return new Nullable<T>(value);
   }
   public static explicit operator T(Nullable<T> value) {
      return value.Value; 
   }
}

我们可以将一个int赋值给Nullable<Int32>,例如Nullable<Int32> x = 2021;,这是因为有隐式转换运算符的存在,它允许我们将int隐式转换为Nullable<Int32>
根据隐式转换运算符的规则,T作为=右侧的操作数时,必须是一个结构体类型。但是,null显然不是一个合法的结构体值,那么我们如何执行Nullable<Int32> y = null;(更不用说Nullable<Int32>本身就是一个结构体了),而且为什么它不违反隐式转换运算符的规则呢?

3
它在语言规范中明确说明,并且被编译器特殊处理。 - undefined
点击这里查看有关可空类型的一些规范,以及点击这里查看有关隐式转换null和可空值类型之间的位的说明。Nullable<T>非常特殊,因为它甚至具有运行时支持:int? x = null; object o = x将一个空引用赋给o,而不是装箱的Nullable<T>,并且拆箱操作也类似。 - undefined
1个回答

3

通过编译器,检查值是否为 null,并将其赋给类型为 Nullable<T> 的变量。这一过程被明确覆盖。

因此,

int? i = ...
if (i == null) ...

被转换为

if (!i.HasValue)

并且

i = null;

被转换为

i = default(Nullable<int>);

一个 default(Nullable<int>) 分配一个“空”(零初始化)的 Nullable<int>。因此,它的 HasValue 属性为 false,这相当于一个 int?null


从来没有太认真地考虑过这个问题,但我一直以为这个 Nullable<DateTime> foo = null; foo.Value.Date; 会抛出一个 NullReferenceException,但今天我才知道它实际上只会抛出一个 InvalidOperationException: Nullable object must have a value. - undefined
对于好奇的人,您可以在此处查看 HasValue 转换 here。 您需要切换到IL视图才能看到它有效地分配了 default(Nullable<int>): 它是 ldloca.s / initobj,它将变量零初始化(与分配 default 相同)。 - undefined
1
如果你想看更多有趣的东西,也可以点击这里 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接