La razón / problema fundamental es que los diseñadores de la especificación CLS (que define cómo interactúan los lenguajes con .net) no definieron un medio por el cual los miembros de la clase pudieran especificar que deben ser llamados directamente, en lugar de vía callvirt
, sin que la persona que realiza la llamada realice un verificación de referencia nula; Tampoco proporcionó un significado de estructuras definitorias que no estarían sujetas al boxeo "normal".
Si la especificación CLS hubiera definido dicho medio, entonces sería posible que .net siguiera consistentemente el liderazgo establecido por el Modelo de Objeto Común (COM), bajo el cual una referencia de cadena nula se consideraba semánticamente equivalente a una cadena vacía, y para otros tipos de clase inmutables definidos por el usuario que se supone que tienen una semántica de valores para definir igualmente los valores predeterminados. Esencialmente, lo que sucedería sería que cada miembro de String
, por ejemplo, Length
se escribiera como algo así [InvokableOnNull()] int String Length { get { if (this==null) return 0; else return _Length;} }
. Este enfoque habría ofrecido una semántica muy buena para cosas que deberían comportarse como valores, pero debido a problemas de implementación deben almacenarse en el montón. La mayor dificultad con este enfoque es que la semántica de conversión entre estos tipos y Object
podría volverse un poco turbia.
Un enfoque alternativo habría sido permitir la definición de tipos de estructura especiales que no heredaran, Object
sino que tuvieran operaciones de boxeo y desempaquetado personalizadas (que se convertirían a / de algún otro tipo de clase). Bajo tal enfoque, habría un tipo de clase NullableString
que se comporta como lo hace una cadena ahora, y un tipo de estructura en caja personalizada String
, que contendría un único campo Value
de tipo privado String
. El intento de convertir un String
a NullableString
o Object
volvería Value
si no nulo, o String.Empty
si es nulo. Intentando convertir String
, una referencia no nula a una NullableString
instancia almacenaría la referencia en Value
(tal vez almacenando nulo si la longitud fuera cero); emitir cualquier otra referencia arrojaría una excepción.
Aunque las cadenas deben almacenarse en el montón, conceptualmente no hay ninguna razón por la que no deberían comportarse como tipos de valor que tienen un valor predeterminado no nulo. Tenerlos almacenados como una estructura "normal" que contenía una referencia habría sido eficiente para el código que los usó como tipo "cadena", pero habría agregado una capa adicional de indirección e ineficiencia al convertir a "objeto". Si bien no preveo que .net agregue ninguna de las características anteriores en esta fecha tardía, quizás los diseñadores de futuros marcos podrían considerar incluirlas.