Ответ 1
Ваша цитата из MSDN повторяет §4.1.10 спецификации С# 5.0:
Тип с нулевым значением записывается
T?
, гдеT
- это базовый тип. Этот синтаксис является сокращением дляSystem.Nullable<T>
, и две формы могут использоваться взаимозаменяемо.
Но "взаимозаменяемо" - это упрощение. Справедливо, что T?
означает System.Nullable<T>
, но, как вы обнаружили, вы не можете использовать T?
везде, где вы можете использовать System.Nullable<T>
. В частности, вид доступа членов (§7.6.4) в вашем примере требует простого имени (§7.6.2):
[§7.6] Первичные выражения включают простейшие формы выражений.
первично-выражение:
не первично-не-массив создания выражения
массив создание выражениепервично не-массив создания самовыражения
буквальный
простое имя
выражение в скобках
член-доступа...[§7.6.2] Простым именем является либо форма
I
, либо формаI<A1, ..., AK>
, гдеI
- это один идентификатор, а<A1, ..., AK>
- необязательный список аргументов типа.[§7.6.4] Член-доступ является либо формой
E.I
, либо формойE.I<A1, ..., AK>
, гдеE
является первичным выражением,I
является единственным идентификатором и<A1, ..., AK>
является необязательным типом-аргументом-списком.
Nullable<T>
- это простое имя, а T?
isnt, поэтому первая компилируется, а последняя не делает.
Почему разработчикам языка С# требовалось выражение члена-доступа для использования простого имени в отличие от любого типа? Я полагаю, что только они могут сказать наверняка, но, возможно, это требование упростило грамматику: в выражении компилятор может предположить, что ?
всегда является условным (тройным) оператором, а не, возможно, спецификатором типа nullable.
В ретроспективе, однако, это был удачный выбор, который позволил С# 6.0 добавить оператора ?.
без возможности нарушения существующих программ. Например, рассмотрим этот патологический пример:
struct S
{
public bool Equals(int x, int y) { return false; }
}
class C
{
public static void Main()
{
S? S = new S();
Console.WriteLine(S?.Equals(1, 1)); // "True" or "False"?
}
}
Если S?.Equals
анализируется как Nullable<S> . Equals
, вызов статического метода Equals
класса Object
? Или он должен анализироваться как S ?. Equals
, ноль-условный вызов метода экземпляра Equals
переменной S
? Поскольку S?
не является простым именем, его однозначно последнее.