Почему я не могу написать Nullable <Nullable <int>>? - PullRequest
11 голосов
/ 29 сентября 2011

Определение Nullable<T>:

[SerializableAttribute]
public struct Nullable<T> where T : struct, new()

Ограничение where T : struct подразумевает, что T может быть только типом значения.Поэтому я очень хорошо понимаю, что я не могу написать:

Nullable<string> a; //error. makes sense to me

Поскольку string является ссылочным типом, а не типом значения.Но я не совсем понимаю, почему я не могу написать

Nullable<Nullable<int>> b; //error. but why?

Почему это не разрешено?В конце концов, Nullable<int> является типом значения, и, следовательно, это может быть аргумент типа Nullablle<T>.

Когда я компилировал его на ideone, он выдает эту ошибку ( ideone ):

ошибка CS0453: тип int?должен иметь тип значения, не допускающий значения NULL, чтобы использовать его в качестве параметра типа «T» в универсальном типе или методе «System.Nullable». Компиляция завершилась неудачно: 1 ошибка (ов), 0 предупреждений

Ответы [ 5 ]

10 голосов
/ 29 сентября 2011

Поскольку это в спецификации C # (раздел 4.4.4):

Если ограничение является ограничением типа значения (struct), тип A должен удовлетворять одному из следующих условий:

  • A является типом структуры или перечислимым типом, , но не обнуляемым типом .Обратите внимание, что System.ValueType и System.Enum являются ссылочными типами, которые не удовлетворяют этому ограничению.
  • A - это параметр типа, имеющий ограничение типа значения (§10.1.5).
6 голосов
/ 29 сентября 2011

Из раздела 4.1.10 спецификации языка C #:

A необнуляемый тип значения и наоборот - это любой тип значения, кроме System.Nullable<T> и его сокращение T? (для любого T), а также любой параметр типа, для которого задан тип значения, не допускающий значения NULL (т. е. любой параметр типа с ограничением struct).Тип System.Nullable<T> определяет ограничение типа значения для T (§10.1.5), что означает, что базовым типом типа, допускающего значение NULL, может быть любой тип значения, не имеющий значения NULL.Базовый тип типа Nullable не может быть типом NULL или ссылочным типом.Например, int?? и string? являются недопустимыми типами.

4 голосов
/ 29 сентября 2011

Из §10.1.5 спецификации C # 4:

Ограничение типа значения указывает, что аргумент типа, используемый для параметра типа, должен быть типом значения, не допускающим значения NULL.Все ненулевые типы структур, перечислимые типы и параметры типов, имеющие ограничение типа значения, удовлетворяют этому ограничению.Обратите внимание, что, хотя классифицируется как тип значения, обнуляемый тип (§4.1.10) не удовлетворяет ограничению типа значения.Параметр типа, имеющий ограничение типа значения, также не может иметь ограничение конструктора.

2 голосов
/ 06 сентября 2017

Это не совсем ответ, а просто пища для размышлений.

Раунд 1

Nullable<Nullable<int>> a;

ошибка CS0453: тип 'int?' должен быть необнуляемым типом значения, чтобы использовать его как параметр 'T' в универсальном типе или методе 'Nullable'

подсказки Intellisense ... Имя можно упростить


Раунд 2

Nullable<int?> a;

ошибка CS0453: тип 'int?' должен быть необнуляемым типом значения, чтобы использовать его как параметр 'T' в универсальном типе или методе 'Nullable'

подсказки Intellisense ... Имя можно упростить


Раунд 3

int?? a;

ошибка CS1519: неверный токен '??' в объявлении класса, структуры или интерфейса

ошибка CS1525: недопустимый термин "??"


Заключение

int? - это просто краткая оценка Nullable<int>, но не существует такой вещи, как int??, которая является единственным способом, которым я могу представить представление Nullable<Nullable<int>> в короткой руке. Плюс int?? заимствует оператор слияния, поэтому я рад, что это невозможно, потому что это выглядит ужасно. Представь себе int????????????? a; Как бессмысленно.

Наконец, поскольку исходный источник для Nullable не дает никаких ограничений для обеспечения этого, я предполагаю, что это ограничение было встроено в CLR как особый случай, когда типы значений, допускающие значение NULL, были введены в C #.

2 голосов
/ 10 ноября 2016

Как уже говорили другие, спецификация запрещает это.

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

struct Nestable<T> where T : struct { /* ... */ }

new Nestable<Nestable<int>>(); // This works just fine

Запрет на вложенные nullables не может быть выражен с использованием системы типов, доступной вам и мне. Он применяется только в специальном случае в компиляторе (CS0453).


В сторону: Ограничение new(), показанное в вопросе, на самом деле не существует на System.Nullable<T>. Ограничения new() запрещены при использовании ограничения struct.

CS0451: ограничение 'new ()' нельзя использовать с ограничением "struct"

Все структуры в любом случае поддерживают инициализацию по умолчанию.

...