переключатель с VAR / null странное поведение


учитывая следующий код:

string someString = null;
switch (someString)
{
    case string s:
        Console.WriteLine("string s");
        break;
    case var o:
        Console.WriteLine("var o");
        break;
    default:
        Console.WriteLine("default");
        break;
}

почему оператор switch соответствует on case var o?

насколько я понимаю,case string s не совпадает, когда s == null потому что (фактически) (null as string) != null принимает значение false. IntelliSense на VS Code говорит мне, что o это string как хорошо. Есть мысли?


аналогично: C# 7 switch case с нулевыми проверками

3 88

3 ответа:

внутри шаблона switch заявление с помощью case для явного типа задает вопрос, Является ли рассматриваемое значение этого конкретного типа или производным типом. Это точный эквивалент is

switch (someString) {
  case string s:
}
if (someString is string) 

значение null не имеет типа и, следовательно, не удовлетворяет ни одному из вышеперечисленных условий. Статический тип someString не вступает в игру ни в одном примере.

The var тип, хотя в сопоставлении шаблонов действует как дикая карта и будет соответствовать любому значению в том числе null.

The default случай вот мертвый код. Элемент case var o будет соответствовать любому значению, null или non-null. Нестандартный случай всегда выигрывает по умолчанию, следовательно,default никогда не будет хитом. Если вы посмотрите на IL, вы увидите, что он даже не испускается.

на первый взгляд может показаться странным, что это компилируется без предупреждения (определенно сбил меня с толку). Но это соответствует поведению C#, которое восходит к 1.0. Компилятор позволяет default случаи, даже когда он может тривиально доказать, что он никогда не будет поражен. Рассмотрим в качестве примера следующее:

bool b = ...;
switch (b) {
  case true: ...
  case false: ...
  default: ...
}

здесь default никогда не будет поражен (даже для bool которые имеют значение, которое не является 1 или 0). Тем не менее, C# разрешил это с 1.0 без предупреждения. Сопоставление с образцом-это просто падение в соответствии с этим поведение.

я собираю несколько комментариев twitter здесь - это на самом деле ново для меня, и я надеюсь, что jaredpar будет прыгать с более полным ответом, но; короткая версия, как я понимаю:

case string s:

трактуется как if(someString is string) { s = (string)someString; ... или if((s = (someString as string)) != null) { ... } - каждый из которых включает в себя null тест-который не удалось в вашем случае; наоборот:

case var o:

где компилятор o как string просто o = (string)someString; ... - нет

потому что case <Type> совпадает с динамический (время выполнения) тип, а не статический (время компиляции) тип. null не имеет динамического типа, поэтому он не может совпадать с string. var - это только запасной вариант.

(сообщение, потому что мне нравятся короткие ответы.)