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