Qualcosa mi è appena venuto in mente oggi che mi ha graffiato la testa.Com'è possibile il comportamento di boxe/unboxing di Nullable <T>?
Qualsiasi variabile di tipo Nullable<T>
può essere assegnata a null
. Per esempio:
int? i = null;
All'inizio non potuto vedere come questo sarebbe possibile senza definire in qualche modo una conversione implicita da object
a Nullable<T>
:
public static implicit operator Nullable<T>(object box);
Ma l'operatore sopra chiaramente non esiste, come se così fosse allora la seguente avrebbe anche dovuto essere legale, almeno al momento della compilazione (che non è):
int? i = new object();
poi ho capito che pe rhaps il tipo Nullable<T>
potrebbe definire una conversione implicita a qualche tipo di riferimento arbitrario che non può mai essere istanziato, in questo modo:
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();
}
}
Tuttavia, questo non spiega ciò che è accaduto a me la prossima: se la proprietà HasValue
è false
per qualsiasi Nullable<T>
valore, allora tale valore verrà imballata come null
:
int? i = new int?();
object x = i; // Now x is null.
Inoltre, se HasValue
è true
, quindi il valore sono imballati come T
piuttosto che un T?
:
int? i = 5;
object x = i; // Now x is a boxed int, NOT a boxed Nullable<int>.
Ma questo sembra implicare che v'è una conversione implicita personalizzato da Nullable<T>
a object
:
public static implicit operator object(Nullable<T> value);
questo non è chiaramente il caso come object
è una classe base per tutti i tipi e le conversioni implicite definite dall'utente per/da tipi di base sono illegali (come dovrebbero essere).
Sembra che object x = i;
dovrebbe scatola i
come qualsiasi altro tipo di valore, in modo che x.GetType()
si determina lo stesso risultato typeof(int?)
(anziché gettare un NullReferenceException
).
Così ho scavato un po 'intorno e, abbastanza sicuro, si scopre che questo comportamento è specifico per il tipo Nullable<T>
, appositamente definito sia nel C# e le specifiche VB.NET, e non riproducibile in qualsiasi definita dall'utente struct
(C#) o Structure
(VB.NET).
Ecco perché sono ancora confuso.
Questo particolare comportamento di boxe e unboxing sembra impossibile da implementare a mano. Funziona solo perché sia C# che VB.NET danno un trattamento speciale al tipo Nullable<T>
.
Non è teoricamente possibile che un linguaggio di base CLI diversa potrebbe esistere dove
Nullable<T>
non hanno avuto questo trattamento speciale? E il tipoNullable<T>
non presenterebbe quindi comportamento diverso in diverse lingue?In che modo C# e VB.NET raggiungono questo comportamento? È supportato dal CLR? (Cioè, fa il CLR permette un tipo in qualche modo "override" il modo in cui viene confezionato, anche se C# e VB.NET stessi lo vieta?)
E 'anche possibile (in C# o VB.NET) per inscatolare un
Nullable<T>
comeobject
?
È il compilatore JIT che implementa il comportamento. Più qui: http://stackoverflow.com/questions/1583050/performance-surprise-with-as-and-nullable-types/3076525#3076525 –
Mi rendo conto che sono in ritardo di 7 anni per la festa. Ma vorrei suggerire a chiunque sia curioso come me di leggere anche la fonte di riferimento per ulteriori approfondimenti. https://referencesource.microsoft.com/#mscorlib/system/nullable.cs, ffebe438fd9cbf0e – Licht