为什么Nullable HasValue属性不会在Null上抛出NullReferenceException?
请考虑以下代码:
DateTime? ndate = null; Console.WriteLine(ndate.HasValue);
我原本期望一个NullReferenceException,但HasValue确实会返回false。 但是,由于ndate为null,属性调用如何成功,因为没有对象可以调用属性HasValue?
从技术上讲,“ndate”不为null – 它是一个值类型,其值指定为null。
当你写DateTime?
,这只是Nullable
简写,它是一个结构。 从技术上讲,这是无法为空的,因为它不是引用类型。
Nullable
是一个结构,基本上它不能保存null
值。
您的作业实际上被编译成如下所示的内容:
Nullable ndate = new Nullable ();
另一个例子,表达式:
int? a = null;
将生成以下IL:
.locals init (valuetype [mscorlib]System.Nullable`1 V_0) IL_0000: ldloca.s V_0 IL_0002: initobj valuetype [mscorlib]System.Nullable`1
对initobj
操作的调用,该操作将指定地址处的值类型的每个字段初始化为空引用或适当原始类型的0。
总之,这里发生的是默认的struct初始化 。
我原以为NullReferenceException
没有空引用被解除引用,因此不应该期望“NullReferenceException”。 可为空的DateTime不是空引用 。 它是一个空值 。
但是,由于ndate为null,属性调用如何成功,因为没有对象可以调用属性HasValue?
这个问题预示着一个错误的前提。 有一个对象。 有一个可以为空的DateTime表示可以为空的DateTime的空值。 该值是一个对象。
考虑你的代码:
DateTime? ndate = null; Console.WriteLine(ndate.HasValue);
这只是写一些逻辑上类似的东西的简短方法:
DateTime ndate = default(DateTime); bool ndateHasValue = false; Console.WriteLine(ndateHasValue);
可以为空的值类型只是编写代码的一种令人愉快的方式,这意味着“请将一个布尔值附加到此事件上,以跟踪它是否在逻辑上为空”。
真正发生的是实际(非null) Nullable结构被赋值给变量,因此变量不是null但是它的值是。
Synctactic sugar我的朋友……编译器将.HasValue调用转换为不会引发exception的代码:-)