Недопустимая путаница <T>

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

Nullable<Nullable<int>>

тогда как

struct MyNullable <T>
{


}

MyNullable<Nullable<int>> 

НЕ

Ответ 1

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

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

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

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

  • изменения компилятора и платформы, необходимые для достижения 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!

Задание того, что возвращает true, будет очень сложным и значительным накладным расходами во многих операциях с использованием типа Nullable.

Некоторые типы в CLR являются "специальными", примеры - это строки и примитивы, поскольку компилятор и среда выполнения знают много о реализации, используемой друг другом. Таким образом, Nullable является особенным. Так как это уже специальная оболочка в других областях, специальный корпус не имеет большого значения. Преимущество этого заключается в работе с структурами в родовых классах, потому что ни один из них, кроме Nullable, не может сравниваться с null. Это означает, что jit может спокойно считать t == null всегда ложным.

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

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

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

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

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

Ответ 2

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

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

public Nullable(
    T value
)

Тип: T Тип значения.

Ответ 3

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

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

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

Ответ 4

Параметр generic type для Nullable должен быть непустым типом (т.е. тип значения). Это предупреждение компилятора С#, которое я получаю, и это, кажется, имеет смысл. Скажи мне, почему ты хочешь все-таки это сделать? Я лично не вижу смысла и мало смысла для такой декларации.

Ответ 5

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

Цитата из MSDN:

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