Nullable <T>путаница - PullRequest
       25

Nullable <T>путаница

10 голосов
/ 01 марта 2009

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

Nullable<Nullable<int>>

, тогда как

struct MyNullable <T>
{


}

MyNullable<Nullable<int>> 

НЕ

Ответы [ 5 ]

19 голосов
/ 01 марта 2009

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

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

где T: struct
Аргумент типа должен быть типом значения. Можно указать любой тип значения, кроме Nullable.
См. Использование Обнуляемых Типов (Руководство по программированию в 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, не может быть сравнен с нулевым. Это означает, что джит может смело считать 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 >> запрещены.

14 голосов
/ 01 марта 2009

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

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

public Nullable(
    T value
)

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

3 голосов
/ 01 марта 2009

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

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

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

2 голосов
/ 01 марта 2009

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

0 голосов
/ 01 марта 2009

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

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

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

...