Обнуляемая <T> путаница

Почему запрещено следующее?

Nullable<Nullable<int>>

в то время как

struct MyNullable <T>
{


}

MyNullable<Nullable<int>> 

не является

Ответов (5)

Решение

Это связано с тем, что ограничение структуры фактически означает «не допускающий значение NULL», поскольку Nullable, несмотря на то, что он является структурой, допускает значение NULL (может принимать значение NULL) и Nullable<int> не является допустимым параметром типа для внешнего Nullable.

Это явно указано в документации по ограничениям.

где T: struct
Аргумент типа должен быть типом значения. Можно указать любой тип значения, кроме Nullable.
Дополнительные сведения см. В разделе Использование типов, допускающих значение NULL (Руководство по программированию на C#).

Если вам нужно обоснование для этого, вам потребуются комментарии разработчика языка, которые я не могу найти. Однако я бы предположил, что:

  1. изменения компилятора и платформы, необходимые для достижения Nullable в его текущей форме, довольно обширны (и были относительно последним дополнением к выпуску 2.0).
  2. У них есть несколько потенциально сбивающих с толку крайних случаев.

Разрешение эквивалента 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, не может сравниваться с null. Это означает, что jit всегда можно безопасно считать t == null ложным.

Там, где языки предназначены для взаимодействия двух очень разных концепций, вы, как правило, получаете странные, запутанные или опасные крайние случаи. В качестве примера рассмотрим Nullable и операторы равенства

int? x = null;
int? y = null;
Console.WriteLine(x == y); // true
Console.WriteLine(x >= y); // false!     

Предотвращая использование значений Nullable при использовании ограничения struct generic, можно избежать многих неприятных (и неясных) крайних случаев.

Что касается точной части спецификации, которая требует этого из раздела 25.7 (выделено мной):

Ограничение типа значения указывает, что аргумент типа, используемый для параметра типа, должен быть типом значения (§25.7.1). Любой не допускающий значения NULL тип структуры, тип перечисления или параметр типа, имеющий ограничение типа значения, удовлетворяет этому ограничению. Параметр типа, имеющий ограничение типа значения, также не должен иметь ограничения-конструктора. Тип System.Nullable определяет ограничение типа значения, не допускающего значения NULL для T. Таким образом, рекурсивно сконструированные типы форм T ?? и Nullable <Nullable <T >>запрещены.

Nullable является особенным, потому что есть явная поддержка упаковки и распаковки Nullable типов, встроенных в CLR:

Если вы используете box инструкцию MSIL против a Nullable<T>, вы фактически получите null в результате. Нет другого типа значения, который при упаковке давал бы нуль.

Аналогичная и симметричная поддержка распаковки.

Я считаю, что в Nullable s можно использовать только типы значений, не допускающие значения NULL . Поскольку Nullable сам по себе имеет значение NULL, такое вложение запрещено.

С http://msdn.microsoft.com/en-us/library/kwxxazwb.aspx

public Nullable(
    T value
)

Тип: тип значения TA.

Nullable позволяет вам взять тип значения и сделать его как ссылочный тип в том смысле, что значение либо существует, либо нет (равно null). Поскольку ссылочный тип уже допускает значение NULL, это недопустимо.

Цитируется из MSDN :

Структура Nullable (T) поддерживает использование только типа значения в качестве типа, допускающего значение NULL, поскольку ссылочные типы допускают значение NULL по дизайну.

Параметр универсального типа для Nullable сам должен быть типом, не допускающим значения NULL (т. Е. Типом значения). Это предупреждение компилятора C#, которое я получаю, и оно, кажется, имеет смысл. Скажите, а зачем вам вообще такое делать? Я лично не вижу смысла в таком заявлении.