Основна причина / проблема полягає в тому, що конструктори специфікації CLS (яка визначає, як мови взаємодіють з .net) не визначили спосіб, за допомогою якого члени класу могли б вказати, що їх потрібно викликати безпосередньо, а не через callvirt
, без того, щоб абонент виконував нульова перевірка; а також не передбачав безлічі визначальних структур, які не підлягали б "нормальному" боксу.
Якби специфікація CLS визначала такий засіб, тоді .net міг би послідовно слідувати керівництву, встановленому загальною модель об'єкта (COM), згідно з якою нульова посилання рядка вважалася семантично еквівалентною порожній рядку та для інших визначені користувачем типи незмінних класів, які повинні мати значення семантики значень, щоб також визначати значення за замовчуванням. По суті, що трапилося б, було б для кожного члена String
, наприклад, Length
писати як щось подібне [InvokableOnNull()] int String Length { get { if (this==null) return 0; else return _Length;} }
. Цей підхід запропонував би дуже приємну семантику для речей, які повинні вести себе як цінності, але через проблеми з реалізацією потрібно зберігати їх у купі. Найбільша складність цього підходу полягає в тому, що семантика перетворення між такими типами і Object
могла б стати трохи мутною.
Альтернативним підходом було б дозволити визначення типів спеціальних структур, які не успадковували, Object
а натомість мали власні операції боксу та розпакування (які перетворювали б на / з іншого типу класу). При такому підході існували б тип класу, NullableString
який веде себе так, як зараз це рядок, та власний структурований тип структури String
, який би містив єдине приватне поле Value
типу String
. Спроба конвертувати a String
в NullableString
або Object
повернеться, Value
якщо не є null, або String.Empty
якщо null. Спроба привласнення до String
ненульової посилання на NullableString
екземпляр зберігатиме посилання в Value
(можливо, зберігання нуля, якщо довжина дорівнює нулю); кастинг будь-якої іншої посилання кине виняток.
Незважаючи на те, що рядки повинні зберігатися в купі, концептуально немає причини, чому вони не повинні вести себе як типи значень, які мають ненулеве значення за замовчуванням. Зберігання їх як "нормальної" структури, на яку було посилання, було б ефективним для коду, який використовував їх як тип "рядок", але додав би додатковий шар непрямості та неефективності при передачі на "об'єкт". Хоча я не передбачаю .net додавати будь-яку з перерахованих вище функцій в цей пізній час, можливо, дизайнери майбутніх фреймворків можуть розглянути можливість їх включення.