Почему сопоставление шаблонов с нулевым результатом в синтаксических ошибках?

Мне нравится использовать pattern-matching в nullable int т. nullable int int? :

int t  = 42;
object tobj = t;    
if (tobj is int? i)
{
    System.Console.WriteLine($"It is a nullable int of value {i}");
}

Однако это приводит к следующим синтаксическим ошибкам:

"i)" помечено красной волнистой линией.

Выражение компилирует при использовании старого оператора is:

int t = 42;
object tobj = t;    
if (tobj is int?)
{
    System.Console.WriteLine($"It is a nullable int");
}


string t = "fourty two";
object tobj = t;
if (tobj is string s)
{
    System.Console.WriteLine([email protected]"It is a string of value ""{s}"".");
}

Также работает как положено.

(Я использую и протестировал оба и )

Я думал, что это связано с приоритетом оператора. Поэтому я пытался использовать скобки в нескольких местах, но это не помогло.

Почему он дает эти синтаксические ошибки и как их избежать?

Ответ 1

Шаблон типа в его различных формах: x is T y, case T y т.д., Всегда не соответствует, когда x равен null. Это потому, что null не имеет типа, поэтому спрашивает "это null этого типа?" это бессмысленный вопрос.

Поэтому t is int? i t is int? i или t is Nullable<int> i не имеет смысла в качестве шаблона: либо t является целым int, в этом случае t является целым int t is int i все равно совпаду, либо оно равно null, и в этом случае ни один шаблон типа не может привести к совпадению.

И это причина, почему t is int? i t is int? i or t is Nullable<int> i Компилятор не поддерживает и, вероятно, никогда не поддержит его.

Причиной, по которой вы получаете дополнительные ошибки от компилятора при использовании t is int? i t is int? i из-за того, что, например, t is int? "it an int": "no int here" t is int? "it an int": "no int here" является допустимым синтаксисом, поэтому компилятор запутается из-за ваших попыток использовать ? для обнуляемого типа в этом контексте.

Что касается того, как их можно избежать, то очевидный (хотя, вероятно, не очень полезный) ответ таков: не используйте обнуляемые типы в качестве типов в шаблонах типов. Более полезный ответ потребует от вас объяснить, почему вы пытаетесь это сделать.

Ответ 2

Измените свой код на:

int t = 42;
object tobj = t;
if (tobj is Nullable<int> i)
{
    Console.WriteLine($"It is a nullable int of value {i}");
}

Это дает более полезную информацию:

  • CS8116: Недействительно использовать тип "int?" с нулевым значением? в шаблоне; используйте базовый тип 'int' вместо (Не удалось найти документацию о CS8116 для ссылки)

Другие (пользователь @Blue0500 в github) отметили это поведение как ошибку Вопрос Roslyn № 20156. Реагирование на Вопрос Roslyn # 20156, Julien Couvreur от Microsoft сказал, что он думает, что это по дизайну.
Neal Gafter от Microsoft, работающего над Roslyn, также сказал

За исключением tobj is int? i, это все еще оставляет вопрос, почему не разрешено tobj is int? i или tobj is Nullable<int> i.