Подтвердить что ты не робот

Почему невозможно вызвать статические методы на Nullable <T> сокращения?

Я думал, что T? является просто сокращением для Nullable<T> компилятора. Согласно MSDN:

Синтаксис T? является сокращением для Nullable<T>, где T - тип значения. Эти две формы взаимозаменяемы.

Тем не менее, существует небольшая (незначительная) разница: Visual Studio не позволяет мне называть статические методы по сокращению:

bool b1 = Nullable<int>.Equals(1, 2); //no error
bool b2 = int?.Equals(1, 2); //syntax error "Invalid expression term 'int'"

Почему? Есть ли причина для этого ограничения?

4b9b3361

Ответ 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? не является простым именем, его однозначно последнее.

Ответ 2

Пока вы правы в синтаксисе, метод Equals можно вызвать из типа по умолчанию, используя тип Nullable в качестве параметров.

Вы можете попробовать этот unit test с любым желаемым значением:

int? i = 4;
int? j = null;
Assert.AreEqual(Nullable<int>.Equals(i, j), int.Equals(i, j));