Учитывая следующий код:
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 case var o
?
Насколько я понимаю, case string s
это не совпадает, когда, s == null
потому что (эффективно) (null as string) != null
оценивается как ложное. IntelliSense в VS Code сообщает мне, что o
это string
тоже. есть идеи?
Аналогично: C # 7 switch case с нулевыми проверками
o
котороеstring
(подтверждено с помощью дженериков - т.е.Foo(o)
гдеFoo<T>(T template) => typeof(T).Name
) - это очень интересный случай, когдаstring x
ведет себя иначе, чемvar x
даже когдаx
он набирается (компилятором) какstring
var
вообще разрешить в этом контексте. Это похоже на то, что я нашел бы в C ++, а не на языке, который, как предполагается, ведет программиста «в пропасть успеха». Здесьvar
неоднозначно и бесполезно, то, чего дизайн C # обычно старается избегать.switch
может быть непроизносимым - анонимные типы и т. д .; и это не двусмысленно - компилятор явно знает тип; это просто сбивает с толку (по крайней мере, меня), чтоnull
правила такие разные!Ответы:
Внутри оператора сопоставления с образцом
switch
с использованием acase
для явного типа задается вопрос, относится ли значение к этому конкретному типу или к производному типу. Это точный эквивалентis
switch (someString) { case string s: } if (someString is string)
Значение
null
не имеет типа и, следовательно, не удовлетворяет ни одному из вышеуказанных условий. Статический типsomeString
не используется ни в одном из примеров.В
var
Типа , хотя в шаблоне соответствие действует как джокер и будет соответствовать любому значению , включаяnull
.default
Дело здесь мертв код. Вcase var o
Будет соответствовать любое значение, нулевое или ненулевое значение. Случай не по умолчанию всегда побеждает случай по умолчанию, поэтомуdefault
никогда не будет выполнен. Если вы посмотрите на IL, вы увидите, что он даже не испускается.На первый взгляд может показаться странным, что это компилируется без какого-либо предупреждения (определенно меня сбило с толку). Но это соответствует поведению C #, восходящему к версии 1.0. Компилятор допускает
default
случаи, даже если он может тривиально доказать, что в него никогда не попадут. Рассмотрим в качестве примера следующее:bool b = ...; switch (b) { case true: ... case false: ... default: ... }
Здесь
default
никогда не будет попадания (дажеbool
если оно имеет значение, отличное от 1 или 0). Тем не менее, C # позволяет это без предупреждения с версии 1.0. Сопоставление с образцом здесь просто соответствует этому поведению.источник
var
к типу,string
хотя на самом деле это не так (честно говоря, не уверен, какой тип должен быть по общему признанию)var
в примереstring
.csc /stiffUpperLip
null
это действительнаяstring
ссылка, и любаяstring
ссылка (включаяnull
) может быть неявно приведена (с сохранением ссылок) кobject
ссылке, и любаяobject
ссылка, которая есть,null
может быть успешно преобразована (явным образом) в любой другой тип, все еще существующийnull
. Не совсем то же самое с точки зрения системы типов компилятора.Я собираю здесь несколько комментариев в твиттере - это на самом деле для меня в новинку, и я надеюсь, что 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; ...
- нетnull
теста, несмотря на то, что он выглядит похожим на поверхности, только с компилятором, предоставляющим тип.наконец-то:
default:
сюда нельзя добраться , потому что вышеупомянутый случай ловит все. Это может быть ошибка компилятора, поскольку он не выдавал предупреждения о недоступности кода.
Я согласен с тем, что это очень тонко, тонко и запутанно. Но, по-видимому, в
case var o
сценарии используется нулевое распространение (иo?.Length ?? 0
т. Д.). Я согласен , что это странно , что это работает так очень по- разному междуvar o
иstring s
, но это то , что в настоящее время делает компилятор.источник
Это потому, что
case <Type>
соответствует динамическому (во время выполнения) типу, а не статическому (во время компиляции) типу.null
не имеет динамического типа, поэтому не может соответствоватьstring
.var
это просто запасной вариант.(Публикую, потому что мне нравятся короткие ответы.)
источник