Como é possível o comportamento de boxe / unboxing de Nullable <T>?
Algo me ocorreu hoje mais cedo que me fez coçar a cabeça.
Qualquer variável do tipoNullable<T>
pode ser atribuído anull
. Por exemplo:
int? i = null;
No começo, eu não conseguia ver como isso seria possível sem definir de alguma forma uma conversão implícita deobject
paraNullable<T>
:
public static implicit operator Nullable<T>(object box);
Mas o operador acima claramente não existe, como se existisse, o seguinte também teria que ser legal, pelo menos em tempo de compilação (o que não é):
int? i = new object();
Então eu percebi que talvez oNullable<T>
type pode definir uma conversão implícita para algum tipo de referência arbitrário que nunca pode ser instanciado, como este:
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();
}
}
No entanto, isso não explica o que me ocorreu a seguir: se oHasValue
propriedade éfalse
para qualquerNullable<T>
valor, então esse valor será encaixotado comonull
:
int? i = new int?();
object x = i; // Now x is null.
Além disso, seHasValue
étrue
, então o valor será encaixotado como umT
ao invés de umT?
:
int? i = 5;
object x = i; // Now x is a boxed int, NOT a boxed Nullable<int>.
Masesta parece implicar que há uma conversão implícita personalizada deNullable<T>
paraobject
:
public static implicit operator object(Nullable<T> value);
Claramente não é esse o caso,object
é uma classe base para todos os tipos e as conversões implícitas definidas pelo usuário para / dos tipos base são ilegais (como deveriam ser).
Parece queobject x = i;
deve caixai
como qualquer outro tipo de valor, para quex.GetType()
produziria o mesmo resultado quetypeof(int?)
(em vez de lançar umNullReferenceException
)
Então eu procurei um pouco e, com certeza, esse comportamento é específico para oNullable<T>
, especialmente definido nas especificações C # e VB.NET, e não reproduzível em nenhuma definição definida pelo usuáriostruct
(C #) ouStructure
(VB.NET).
Aqui está o porquê de eu ainda estar confuso.
Esse comportamento específico de boxe e unboxing parece ser impossível de implementar manualmente. Só funciona porque o C # e o VB.NET dão tratamento especial aoNullable<T>
tipo.
Não é teoricamente possível que uma linguagem diferente baseada em CLI possa existir ondeNullable<T>
não receberam esse tratamento especial? E nãoNullable<T>
tipo, portanto, exibemcomportamento diferente em diferentes idiomas?
Como C # e VB.NETalcançar esse comportamento? É suportado pelo CLR? (Ou seja, o CLR permite que um tipo "substitua" de alguma maneira a maneira como está dentro da caixa, mesmo que o C # e o VB.NET o proíbam?)
É mesmopossível (em C # ou VB.NET) paraNullable<T>
Comoobject
?