2009-03-27 18 views
33

¿Por qué no está permitido asignar nulo a un DateTime en C#? ¿Cómo se ha implementado esto? ¿Y se puede usar esta característica para hacer que sus propias clases no sean anulables?¿Por qué no se permite nulo para DateTime en C#?

Ejemplo:

string stringTest = null; // Okay 
DateTime dateTimeTest = null; // Compile error 

Sé que puedo usar DateTime? en C# 2.0 para permitir nula que se asignará a dateTimeTest y que podría utilizar Jon Skeet's NonNullable class en mi cadena para obtener un error de tiempo de ejecución en la asignación de stringTest. Me pregunto por qué los dos tipos se comportan de manera diferente.

+0

Es Jon no John. –

Respuesta

76

DateTime es un valor-tipo (struct), donde-como cadena es un tipo de referencia (class etc.). Esa es la diferencia clave. Una referencia siempre puede ser nula; un valor no puede (a menos que use Nullable<T> - es decir, DateTime?), aunque puede ser zero'd (DateTime.MinValue), que a menudo se interpreta como lo mismo que nulo (especialmente en 1.1).

+0

Muchas gracias por la aclaración. ¿Por qué no utilizar structs para crear clases que no admiten nulos? –

+1

¿Y cuál sería el valor predeterminado (YourWrapper)? ;-p Sería una estructura que contiene una referencia nula ... todas las estructuras * siempre * tienen un constructor predeterminado ... –

+0

(o * nunca * tienen un constructor predeterminado, dependiendo de si está hablando de C# o de la CLI - que no están de acuerdo con este punto) –

8

DateTime es una estructura y no una clase. Haga una 'ir a definición' o mírela en el navegador de objetos para ver.

HTH!

1

DateTime es un tipo de valor, igual que un int. Solo los tipos de referencia (como cadena o MyCustomObject) pueden ser nulos. Los tipos de referencia realmente almacenan "referencias" a la ubicación de los objetos en el montón.

he aquí un article Encontré que lo explica mejor. y aquí está el MSDN article on it

+0

O tipos de valores que aceptan valores NULL a través de Nullable (que a su vez también es una estructura) –

0

cadena es una clase, mientras que DateTime es una estructura. Es por eso que no puede configurarlo como nulo

7

La distinción importante entre ValueTypes y tipos de referencia es que los tipos de valores tienen estos "valores semánticos". Un DateTime, Int32 y todos los otros tipos de valores no tienen identidad, un Int32 "42" es esencialmente indistinguible de cualquier otro Int32 con el mismo valor.

Todos los tipos de valor "objetos" existen ya sea en la pila o como parte de un objeto de tipo de referencia. Un caso especial es cuando lanzas una instancia de tipo de valor a un objeto o una interfaz; esto se llama "boxeo", y simplemente crea un objeto tipo referencia ficticio que solo contiene el valor que se puede extraer de nuevo ("unboxed") .

Los tipos de referencia, por otro lado, tienen una identidad. un "nuevo objeto()" no equivale a ningún otro "nuevo objeto()", porque son instancias separadas en el montón de GC. Algunos tipos de referencia proporcionan el método Equals y los operadores sobrecargados para que se comporten de forma similar a los valores, por ejemplo. una cadena "abc" es igual a otra cadena "abc" incluso si en realidad son dos objetos diferentes.

Por lo tanto, cuando tiene una referencia, puede contener la dirección de un objeto válido o puede ser nula. Cuando los objetos de tipo de valor son todos cero, son simplemente cero. P.ej. un entero cero, un flotante cero, booleano falso o DateTime.MinValue. Si necesita distinguir entre "cero" y "valor perdido/nulo", necesita usar un indicador booleano separado o, mejor aún, usar la clase T> Nullable < en .NET 2.0. Que es simplemente el valor más un indicador booleano. También hay soporte en el CLR para que el boxeo de un Nullable con HasValue = falso resulte en una referencia nula, no en una estructura enmarcada con falso + cero, como lo haría si implementara esta estructura usted mismo.

1

Para que un tipo de valor sea nulo, debe haber algún valor que pueda contener que no tenga ningún otro significado legítimo, y que el sistema de alguna manera sepa que debe considerarse como "nulo". Algunos tipos de valores podrían cumplir el primer criterio sin requerir ningún almacenamiento adicional. Si .net había sido diseñado desde cero con el concepto de valores con valores nulos en cuenta, podría haber tenido Object include a virtual IsLogicalNull property, and a non-virtual EsNulo which would return cierto if este is null and, otherwise invoke its IsLogicalNull property and return the result. If .net had done this, it would have avoided the need for the quirky boxing behavior and estructura constraint of anulable (an empty anulable could be boxed as an empty anulable , and still be recognized as null`).

En el momento en que se decidió proporcionar apoyo a los tipos de valores con valores nulos en .NET 2.0, sin embargo, una gran cantidad de código había sido escrito, que supone que los valores por defecto para cosas como GuidDateTime y no serían consideradas como null. Dado que gran parte del valor de los tipos que aceptan nulos reside en su valor predeterminado predecible (es decir, null), tener tipos que tenían un valor de null, pero predeterminados a otra cosa, habría agregado más confusión que valor.

Cuestiones relacionadas