¿Cómo es posible el comportamiento de boxing / unboxing de Nullable <T>?
Hoy se me ocurrió algo que me hizo rascarme la cabeza.
Cualquier variable de tipoNullable<T>
puede ser asignado anull
. Por ejemplo:
int? i = null;
Al principio no podía ver cómo esto sería posible sin definir de alguna manera una conversión implícita deobject
aNullable<T>
:
public static implicit operator Nullable<T>(object box);
Pero el operador anterior claramente no existe, como si existiera, entonces lo siguiente también debería ser legal, al menos en tiempo de compilación (que no lo es):
int? i = new object();
Entonces me di cuenta de que tal vez elNullable<T>
tipo podría definir una conversión implícita a algún tipo de referencia arbitraria que nunca puede ser instanciada, como esta:
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();
}
}
Sin embargo, esto no explica lo que se me ocurrió a continuación: si elHasValue
la propiedad esfalse
para cualquierNullable<T>
valor, entonces ese valor se encuadrará comonull
:
int? i = new int?();
object x = i; // Now x is null.
Además, siHasValue
estrue
, entonces el valor será encuadrado como unT
preferible aT?
:
int? i = 5;
object x = i; // Now x is a boxed int, NOT a boxed Nullable<int>.
Peroesta parece implicar que hay una conversión implícita personalizada deNullable<T>
aobject
:
public static implicit operator object(Nullable<T> value);
Esto claramente no es el caso comoobject
es una clase base para todos los tipos, y las conversiones implícitas definidas por el usuario a / desde los tipos base son ilegales (también deberían serlo).
Parece queobject x = i;
debe cajai
como cualquier otro tipo de valor, de modo quex.GetType()
daría el mismo resultado quetypeof(int?)
(en lugar de tirar unNullReferenceException
)
Así que busqué un poco y, efectivamente, este comportamiento es específico para elNullable<T>
tipo, especialmente definido en las especificaciones C # y VB.NET, y no reproducible en ningún tipo definido por el usuariostruct
(C #) oStructure
(VB.NET).
He aquí por qué sigo confundido.
Este comportamiento particular de boxeo y desempaquetado parece ser imposible de implementar a mano. Solo funciona porque C # y VB.NET le dan un tratamiento especial aNullable<T>
tipo.
¿No es teóricamente posible que exista un lenguaje diferente basado en CLI dondeNullable<T>
¿No recibieron este tratamiento especial? Y no sería elNullable<T>
tipo por lo tanto exhibircomportamiento diferente en diferentes idiomas?
¿Cómo C # y VB.NETlograr ¿este comportamiento? ¿Es compatible con el CLR? (Es decir, ¿permite el CLR que un tipo de alguna manera "anule" la forma en que está encuadrado, aunque C # y VB.NET lo prohíben?)
Es inclusoposible (en C # o VB.NET) para boxear unNullable<T>
comoobject
?