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, Lengthser 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 Objectpode ficar um pouco obscura.
Uma abordagem alternativa seria permitir a definição de tipos de estrutura especiais que não foram herdados, Objectmas 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 NullableStringque se comporta como a string agora e um tipo de estrutura personalizada String, que conteria um único campo particular Valuedo tipo String. A tentativa de converter um Stringpara NullableStringou Objectretornaria Valuese não for nulo ou String.Emptyse for nulo. Tentando converter para String, uma referência não nula a uma NullableStringinstâ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.