A razão / problema fundamental é que os projetistas da especificação CLS (que definem como as linguagens interagem com .net) não definiram um meio pelo qual os membros da classe pudessem especificar que deveriam ser chamados diretamente, e não via callvirt
, sem que o chamador realizasse uma chamada. verificação de referência nula; nem forneceu um meio de definir estruturas que não estariam sujeitas ao boxe "normal".
Se a especificação CLS definisse esses meios, seria possível que o .net seguisse consistentemente o lead estabelecido pelo Common Object Model (COM), sob o qual uma referência de cadeia nula fosse considerada semanticamente equivalente a uma cadeia vazia e por outras tipos de classe imutáveis definidos pelo usuário que deveriam ter semântica de valores para definir da mesma forma os valores padrão. Essencialmente, o que aconteceria seria para cada membro String
, por exemplo, Length
ser escrito como algo parecido [InvokableOnNull()] int String Length { get { if (this==null) return 0; else return _Length;} }
. Essa abordagem ofereceria semântica muito boa para coisas que deveriam se comportar como valores, mas, devido a problemas de implementação, precisam ser armazenados no heap. A maior dificuldade com essa abordagem é que a semântica da conversão entre esses tipos e Object
pode ficar um pouco obscura.
Uma abordagem alternativa seria permitir a definição de tipos de estrutura especiais que não foram herdados, Object
mas que tinham operações personalizadas de boxe e unboxing (que seriam convertidas para / de outro tipo de classe). Sob essa abordagem, haveria um tipo de classe NullableString
que se comporta como a string agora e um tipo de estrutura personalizada String
, que conteria um único campo particular Value
do tipo String
. A tentativa de converter um String
para NullableString
ou Object
retornaria Value
se não for nulo ou String.Empty
se for nulo. Tentando converter para String
, uma referência não nula a uma NullableString
instância armazenaria a referência Value
(talvez armazenando nulo se o comprimento fosse zero); lançar qualquer outra referência lançaria uma exceção.
Mesmo que as strings precisem ser armazenadas no heap, conceitualmente não há razão para que elas não devam se comportar como tipos de valor que possuem um valor padrão não nulo. Tê-los armazenados como uma estrutura "normal", que continha uma referência, seria eficiente para o código que os utilizava como tipo "string", mas teria adicionado uma camada extra de indireção e ineficiência ao converter para "objeto". Embora eu não preveja o .net adicionando um dos recursos acima até essa data tardia, talvez designers de estruturas futuras possam considerar a possibilidade de incluí-los.