Это связано с тем, что структурное ограничение фактически означает 'не обнуляемый' , поскольку Nullable, несмотря на то, что он является структурой, может обнуляться (может принимать значение null), Nullable<int>
не является допустимым параметром типа для наружный Nullable.
Это явно указано в документации по ограничениям
где T: struct
Аргумент типа должен быть типом значения. Можно указать любой тип значения, кроме Nullable.
См. Использование Обнуляемых Типов (Руководство по программированию в C #) для получения дополнительной информации.
Если вы хотите получить обоснование для этого, вам понадобятся комментарии фактического дизайнера языка, которые я не могу найти. Однако я бы постулировал, что:
- изменения в компиляторе и платформе, необходимые для достижения Nullable в его текущей форме, довольно обширны (и были сравнительно последним дополнением к версии 2.0).
- У них есть несколько потенциально запутанных крайних случаев.
Разрешение эквивалентно int ?? только запутает, что, поскольку язык не предоставляет никакого способа отличить Nullable <Nullable<null>>
и Nullable <null>
, ни какое-либо очевидное решение для следующего.
Nullable<Nullable<int>> x = null;
Nullable<int> y = null;
Console.WriteLine(x == null); // true
Console.WriteLine(y == null); // true
Console.WriteLine(x == y); // false or a compile time error!
Принятие этого возвращаемого значения будет очень сложным и значительным по многим операциям, связанным с типом Nullable.
Некоторые типы в CLR являются «специальными», примерами являются строки и примитивы, в которых компилятор и среда выполнения много знают о реализации, используемой друг другом. Nullable также особенный в этом смысле. Поскольку это уже специальный корпус в других областях, специальный корпус аспекта where T : struct
не имеет большого значения. Преимущество этого заключается в работе со структурами в общих классах, поскольку ни один из них, кроме Nullable, не может быть сравнен с нулевым. Это означает, что джит может смело считать t == null
ложным всегда.
В тех случаях, когда языки предназначены для взаимодействия двух совершенно разных концепций, вы, как правило, получаете странные, запутывающие или приводящие в порядок опасные крайности. В качестве примера рассмотрим Nullable и операторы равенства
int? x = null;
int? y = null;
Console.WriteLine(x == y); // true
Console.WriteLine(x >= y); // false!
Предотвращая Nullables при использовании структурных общих ограничений, можно избежать многих неприятных (и неясных) крайних случаев.
Что касается точной части спецификации, которая предписывает это из раздела 25.7 (выделено мое):
Ограничение типа значения указывает, что аргумент типа используется для параметра типа
должен быть типом значения (§25.7.1). Любой необнуляемый тип структуры, тип перечисления или тип
параметр, имеющий ограничение типа значения, удовлетворяет этому ограничению. Параметр типа
наличие ограничения типа значения также не должно иметь ограничения конструктора.
Тип System.Nullable задает ограничение на необнуляемое значение типа для T.
Таким образом, рекурсивно сконструированные типы форм T ?? и Nullable <
Nullable <
T >>
запрещены.