为什么在C#中DateTime类型不允许为null?

40
为什么在C#中不允许将null赋值给DateTime?这是如何实现的?该特性是否可用于使您自己的类不可为空?
示例:
string stringTest = null; // Okay
DateTime dateTimeTest = null; // Compile error

我知道在C# 2.0中可以使用DateTime?来允许将null分配给dateTimeTest,并且我可以在字符串上使用Jon Skeet的NonNullable类,以在分配stringTest时获取运行时错误。我只是想知道这两种类型为什么表现不同。

6个回答

89

DateTime是一个值类型(struct),而字符串是一个引用类型(class等)。 这是它们之间的关键区别。 引用可以始终为null; 值不能(除非它使用Nullable<T> - 即DateTime?),尽管它可以被赋为零(DateTime.MinValue),这经常被解释为与null相同的东西(特别是在1.1版本中)。


非常感谢您的澄清。为什么不使用结构体来创建非空类呢? - Jan Aagaard
1
默认情况下(YourWrapper)会是什么?;-p 它将是一个包含空引用的结构体...所有结构体始终具有默认构造函数... - Marc Gravell
(或者根据你所讨论的是C#还是CLI而定,可能没有默认构造函数) - Marc Gravell
Marc,你的回答真是太棒了。简洁明了,重点突出! - Cherian
谢谢您建议使用MinValue,我正在寻找一些方法来返回一个值,以防找不到某个值。正是我需要的! - BMB

9

DateTime是一个结构体而不是类。可以通过“转到定义”或在对象浏览器中查看它。

希望对你有所帮助!


7
ValueTypes和引用类型之间的重要区别在于ValueTypes具有“值语义”。DateTime、Int32以及所有其他值类型都没有身份,一个Int32“42”与具有相同值的任何其他Int32本质上是无法区分的。
所有值类型“对象”都存在于堆栈上或作为引用类型对象的一部分。一个特殊情况是,当你将一个值类型实例强制转换为Object或接口时 - 这被称为“装箱”,它只是创建了一个虚拟的引用类型对象,它仅包含可以提取回来的值(“拆箱”)。
另一方面,引用类型具有身份。一个“new Object()”不等于任何其他“new Object()”,因为它们是GC堆上的单独实例。一些引用类型提供Equals方法和重载运算符,以便它们表现得更像值类型,例如String“abc”等于其他“abc” String,即使它们实际上是两个不同的对象。
所以当你有一个引用时,它可能包含一个有效对象的地址,也可能为null。当值类型对象都是零时,它们就是零。例如,整数零、浮点零、Boolean false或DateTime.MinValue。如果你需要区分“零”和“值缺失/空”,你需要使用一个单独的布尔标志,或者更好地使用.NET 2.0中的Nullable类。这只是一个值加上一个布尔标志。CLR也支持Nullable的装箱,当HasValue=false时,结果为null引用,而不是在自己实现这个结构的情况下,生成一个带有false+zero的装箱结构。

1

DateTime是一个值类型,与int一样。只有引用类型(如字符串或MyCustomObject)才可以为空。引用类型实际上存储了指向堆上对象位置的"引用"。

这里有一篇文章,讲解得更清楚。而这里是MSDN关于此的文章


或者通过 Nullable<T>(它本身也是一个结构体)来使用可空值类型。 - Marc Gravell

1

对于值类型来说,要使其为null,必须有一些它可以持有的值,这些值没有其他合法的含义,并且系统会以某种方式知道应该将其视为“null”。一些值类型可以满足第一个条件而不需要任何额外的存储空间。如果.net从一开始就考虑了可空值的概念,它可能会在Object中包含一个虚拟的IsLogicalNull属性和一个非虚拟的IsNull属性,如果this为null,则返回true,否则调用其IsLogicalNull属性并返回结果。如果.net这样做,就可以避免需要奇怪的装箱行为和Nullable的结构约束(一个空的Nullable可以被装箱为一个空的Nullable,并仍然被识别为null)。

到决定在 .NET Framework 2.0 中为可空值类型提供支持的时候,很多代码已经编写了,这些代码假定像 GuidDateTime 这样的默认值不会被视为 null。由于可为空类型的很多价值都在于它们可预测的默认值(即 null),因此拥有一个可以具有 null 值但默认为其他值的类型,可能会增加更多混乱而不是价值。

0

string是一个类,而DateTime是一个结构。这就是为什么你不能将其设置为null的原因。


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