为什么不允许在C#中为DateTime分配null?这是如何实现的?是否可以使用此功能使您自己的类不可为空?
示例:
string stringTest = null; // Okay
DateTime dateTimeTest = null; // Compile error
我知道我可以在C#2.0中使用DateTime?
来允许将null分配给dateTimeTest,并且我可以在我的字符串上使用Jon Skeet's NonNullable class来获取stringTest赋值的运行时错误。我只是想知道为什么这两种类型的行为不同。
答案 0 :(得分:83)
DateTime
是一个值类型(struct
),其中-string是引用类型(class
等)。这是关键的区别。引用始终为null;值不能(除非它使用Nullable<T>
- 即DateTime?
),尽管它可以为零(DateTime.MinValue
),这通常被解释为与null相同(esp)在1.1)。
答案 1 :(得分:9)
DateTime是一个结构而不是一个类。做一个'去定义'或在对象浏览器中查看它。
HTH!
答案 2 :(得分:7)
ValueTypes和引用类型之间的重要区别是值类型具有这些“值语义”。 DateTime,Int32和所有其他值类型都没有标识,Int32“42”基本上与具有相同值的任何其他Int32无法区分。
所有值类型“对象”都存在于堆栈上或作为引用类型对象的一部分。一个特例是当你将一个值类型实例转换为一个Object或一个接口时 - 这称为“boxing”,它只是创建一个虚拟引用类型对象,它只包含可以提取回的值(“unboxed”)
另一方面,引用类型具有标识。 “new Object()”不等于任何其他“new Object()”,因为它们是GC堆上的单独实例。一些引用类型提供了Equals方法和重载运算符,因此它们的行为更像值,例如。字符串“abc”等于其他“abc”字符串,即使它们实际上是两个不同的对象。
因此,当您有引用时,它可以包含有效对象的地址,也可以为null。当值类型对象全为零时,它们只是零。例如。整数零,浮点零,布尔值false或DateTime.MinValue。如果你需要区分“零”和“值缺失/空”,你需要使用一个单独的布尔标志,或者更好的是,使用Nullable&lt; T&gt;。 .NET 2.0中的类。这只是值加上一个布尔标志。在CLR中也有支持,因此使用HasValue = false对Nullable进行装箱会导致空引用,而不是带有false + 0的盒装结构,就像你自己实现这个结构一样。
答案 3 :(得分:1)
DateTime是一个值类型,与int相同。只有引用类型(如string或MyCustomObject)可以为null。引用类型实际上将“引用”存储到堆上的对象位置。
这是article我发现更好地解释了它。这是MSDN article on it
答案 4 :(得分:1)
对于value-type为null,必须有一些它可以容纳的值没有其他合法含义,系统将以某种方式知道的应该被视为“null”。某些值类型可以满足第一个标准,而无需任何额外的存储空间。如果.net是从头开始设计的,考虑到可空值的概念,它可能有Object include a virtual
IsLogicalNull property, and a non-virtual
IsNull which would return
为真if
这个{{1 }} {IsLogicalNull {1}} {结构{1}}可为空的is null and, otherwise invoke its
可为空的property and return the result. If .net had done this, it would have avoided the need for the quirky boxing behavior and
可为空的constraint of
null`)。
当决定在.net framework 2.0中为可空值类型提供支持时,已经编写了许多代码,假设(an empty
和{{1}之类的内容的默认值}不会被视为could be boxed as an empty
。由于可空类型中的大部分值都在于其可预测的默认值(即, and still be recognized as
),因此具有Guid
值但默认为其他类型的类型会增加混淆而不是值。< / p>
答案 5 :(得分:0)
string是一个类,而DateTime是一个结构。这就是为什么你不能把它设置为null