2009-03-27 17 views
33

Warum ist es nicht erlaubt, eine DateTime in C# Null zuzuordnen? Wie wurde das umgesetzt? Und kann diese Funktion verwendet werden, um Ihre eigenen Klassen nicht nullfähig zu machen?Warum ist NULL für DateTime in C# nicht zulässig?

Beispiel:

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

Ich weiß, dass ich DateTime? in C# 2.0 zu ermöglichen null dateTimeTest zugewiesen werden kann, und dass ich Jon Skeet's NonNullable class auf meinem String erhalten einen Laufzeitfehler auf der Zuordnung verwenden könnte von ZeichenfolgeTest. Ich frage mich nur, warum sich die beiden Typen anders verhalten.

+0

Es ist Jon nicht John. –

Antwort

76

DateTime ist ein Werttyp (struct), wobei als String ein Referenztyp (class usw.) ist. Das ist der Hauptunterschied. Eine Referenz kann immer null sein; ein Wert kann nicht (außer Nullable<T> - d. h. DateTime?) verwendet werden, obwohl er null sein kann (DateTime.MinValue), was oft als das Gleiche wie Null interpretiert wird (insbesondere in 1.1).

+0

Vielen Dank für die Klärung. Warum verwenden Sie keine Strukturen, um nicht nullbare Klassen zu erstellen? –

+1

Und was wäre Standard (YourWrapper)? ;-p Es wäre eine Struktur, die einen NULL-Verweis enthält ... Alle Strukturen * immer * haben einen Standardkonstruktor ... –

+0

(oder * niemals * haben einen Standardkonstruktor, je nachdem, ob Sie über C# oder das CLI sprechen - die in diesem Punkt nicht übereinstimmen) –

8

DateTime ist eine Struktur und keine Klasse. Machen Sie eine 'go to definition' oder schauen Sie im Objektbrowser nach, um zu sehen.

HTH!

1

DateTime ist ein Werttyp, der einem int entspricht. Nur Referenztypen (wie String oder MyCustomObject) können null sein. Referenztypen speichern wirklich "Referenzen" auf den Objektort auf dem Heap.

hier ist ein article Ich fand, dass es besser erklärt. und hier ist die MSDN article on it

+0

Oder Nullable-Werttypen über Nullable (die selbst auch eine Struktur ist) –

0

Zeichenfolge ist eine Klasse, während DateTime eine Struktur ist. Deshalb können Sie ihn nicht auf null setzen

7

Der wichtige Unterschied zwischen ValueTypes und Referenztypen besteht darin, dass Werttypen diese "Wertesemantik" haben. Ein DateTime, Int32 und alle anderen Werttypen haben keine Identität, ein Int32 "42" ist im Wesentlichen von keinem anderen Int32 mit dem gleichen Wert zu unterscheiden.

Alle Werttyp "Objekte" existieren entweder auf Stapel oder als Teil eines Referenztypobjekts. Ein spezieller Fall ist, wenn Sie eine Werttyp-Instanz auf ein Objekt oder eine Schnittstelle werfen - dies wird "Boxen" genannt und erzeugt einfach ein Dummy-Objekt vom Referenztyp, das nur den Wert enthält, der zurück extrahiert werden kann ("ungepackt"). .

Referenztypen haben auf der anderen Seite eine Identität. Ein "neues Objekt()" ist keinem anderen "neuen Objekt()" gleich, da es sich um separate Instanzen auf dem GC-Heap handelt. Einige Referenztypen bieten eine Equals-Methode und überladene Operatoren, so dass sie sich wertvoller verhalten, z. Eine Zeichenkette "abc" ist gleichbedeutend mit einer anderen "abc" Zeichenkette, auch wenn es sich tatsächlich um zwei verschiedene Objekte handelt.

Wenn Sie also einen Verweis haben, kann er entweder die Adresse eines gültigen Objekts enthalten oder er kann null sein. Wenn Werttyp-Objekte alle null sind, sind sie einfach Null. Z.B. eine Ganzzahl Null, eine Gleitkommazahl Null, Boolean false oder DateTime.MinValue. Wenn Sie zwischen "Null" und "Wert fehlt/Null" unterscheiden müssen, müssen Sie entweder ein separates boolesches Flag verwenden oder, noch besser, verwenden Sie die Nullable < T> -Klasse in .NET 2.0. Was ist einfach der Wert plus ein boolesches Flag. Es gibt auch Unterstützung in der CLR, so dass das Boxen einer Nullable mit HasValue = false zu einer Nullreferenz führt und nicht in einer Boxed-Struktur mit false + zero, wie wenn Sie diese Struktur selbst implementieren würden.

1

Damit ein Wert-Typ Null ist, muss es einen Wert enthalten, der keine andere legitime Bedeutung haben könnte, und , von dem das System irgendwie weiß, sollte als "Null" betrachtet werden. Einige Werttypen könnten das erste Kriterium erfüllen, ohne dass zusätzlicher Speicher erforderlich wäre. Wenn .net von Grund auf mit dem Konzept der Nullable-Werte im Verstand entworfen worden war, konnte es Object include a virtual IsLogicalNull property, and a non-virtual IsNull which would return wahr if diese 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 struct constraint of(an empty Nullable Nullable could be boxed as an empty Nullable , and still be recognized as null`) gehabt haben.

Mit der Zeit wurde beschlossen, die Unterstützung für Nullable-Wertetypen in .net 2.0 zu bieten, hatte jedoch bereits eine Menge Code geschrieben, für Dinge wie Guid und DateTime dass die Standardwerte angenommen würden als null nicht angesehen werden. Da ein großer Teil des Wertes in Nullable-Typen mit ihrem vorhersagbaren Standardwert (d. H. null) liegt, hätte das Hinzufügen von Typen mit einem null-Wert, die jedoch auf etwas anderes zurückgesetzt wurden, zu mehr Verwirrung als Wert geführt.