Mir ist heute etwas aufgefallen, das mich am Kopf kratzen lässt.
Jede Variable vom Typ Nullable<T>
können zugeordnet werden zu null
. Zum Beispiel:
int? i = null;
Zunächst konnte ich nicht erkennen, wie dies möglich sein sollte, ohne irgendwie eine implizite Umwandlung von object
à Nullable<T>
:
public static implicit operator Nullable<T>(object box);
Aber der obige Operator existiert eindeutig nicht, denn wenn er es täte, dann müsste auch das Folgende legal sein, zumindest zur Kompilierzeit (was es nicht ist):
int? i = new object();
Dann wurde mir klar, dass vielleicht die Nullable<T>
Typ könnte eine implizite Konvertierung in einen beliebigen Referenztyp definieren, der niemals instanziiert werden kann, etwa so:
public abstract class DummyBox
{
private DummyBox()
{ }
}
public struct Nullable<T> where T : struct
{
public static implicit operator Nullable<T>(DummyBox box)
{
if (box == null)
{
return new Nullable<T>();
}
// This should never be possible, as a DummyBox cannot be instantiated.
throw new InvalidCastException();
}
}
Dies erklärt jedoch nicht, was mir als nächstes einfiel: Wenn die HasValue
Eigenschaft ist false
für jede Nullable<T>
Wert, dann wird dieser Wert in einem Kasten als null
:
int? i = new int?();
object x = i; // Now x is null.
Außerdem, wenn HasValue
es true
, dann wird der Wert in einem Kasten als T
und nicht eine T?
:
int? i = 5;
object x = i; // Now x is a boxed int, NOT a boxed Nullable<int>.
Aber este scheint zu implizieren, dass es eine eigene implizite Konvertierung von Nullable<T>
à object
:
public static implicit operator object(Nullable<T> value);
Dies ist eindeutig nicht der Fall, da object
ist eine Basisklasse für alle Typen, und benutzerdefinierte implizite Konvertierungen in/aus Basistypen sind illegal (was sie auch sein sollten).
Es scheint, dass object x = i;
sollte boxen i
wie jeder andere Werttyp, so dass x.GetType()
würde das gleiche Ergebnis liefern wie typeof(int?)
(anstatt eine NullReferenceException
).
Also habe ich ein wenig geforscht, und es stellte sich heraus, dass dieses Verhalten spezifisch für die Nullable<T>
Typ, der sowohl in der C#- als auch in der VB.NET-Spezifikation speziell definiert ist und in keiner benutzerdefinierten Datei reproduzierbar ist struct
(C#) oder Structure
(VB.NET).
Das ist der Grund, warum ich immer noch verwirrt bin.
Dieses spezielle Boxing- und Unboxing-Verhalten scheint unmöglich von Hand zu implementieren zu sein. Es funktioniert nur, weil sowohl C# als auch VB.NET eine Sonderbehandlung für die Nullable<T>
Typ.
-
Ist es nicht theoretisch möglich, dass eine andere CLI-basierte Sprache existiert, in der
Nullable<T>
diese Sonderbehandlung nicht erhalten haben? Und würde nicht dieNullable<T>
Typ weisen daher auf anderes Verhalten in verschiedenen Sprachen? -
Wie funktionieren C# und VB.NET erreichen dieses Verhalten? Wird es von der CLR unterstützt (d. h., erlaubt die CLR, dass ein Typ die Art und Weise, in der er gepackt wird, irgendwie "außer Kraft setzt", obwohl C# und VB.NET dies selbst verbieten)?
-
Ist es überhaupt möglich (in C# oder VB.NET), um eine
Nullable<T>
commeobject
?