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?

questionAnswers(3)

yourAnswerToTheQuestion