przełącznik z var / null dziwne zachowanie
Podano następujący kod:
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;
}
Dlaczego polecenie switch pasuje do case var o
?
Rozumiem, że case string s
nie pasuje, Kiedy s == null
, ponieważ (skutecznie) (null as string) != null
ocenia NA false. IntelliSense NA VS Code mówi mi, że o
jest string
również. Jakieś pomysły?
Podobne do: C # 7 switch case with null checks
3 answers
Wewnątrz dopasowującej się do wzorca instrukcji switch
używanie case
dla jawnego typu jest pytaniem, czy dana wartość jest tego konkretnego typu, Czy typu pochodnego. Jest dokładnym odpowiednikiem is
switch (someString) {
case string s:
}
if (someString is string)
Wartość null
nie ma typu i dlatego nie spełnia żadnego z powyższych warunków. Typ statyczny someString
nie wchodzi w grę w żadnym z przykładów.
Typ var
w pattern matching działa jak dzika karta i dopasuje dowolną wartość, w tym null
.
Sprawa tutaj to martwy kod. case var o
dopasuje dowolną wartość, null lub non-null. Nie-domyślny przypadek zawsze wygrywa z domyślnym, dlatego default
nigdy nie zostanie trafiony. Jeśli spojrzysz na IL zobaczysz, że nawet nie jest emitowane.
Na pierwszy rzut oka może się wydawać dziwne, że to kompiluje się bez żadnego ostrzeżenia(zdecydowanie mnie wyrzuciło). Ale to jest dopasowanie do zachowania C#, które wraca do 1.0. Kompilator pozwala default
na przypadki nawet wtedy, gdy może trywialnie udowodnić, że będzie nigdy nie daj się trafić. Rozważmy jako przykład:
bool b = ...;
switch (b) {
case true: ...
case false: ...
default: ...
}
Tutaj default
nigdy nie zostanie trafiony (nawet dla bool
, które mają wartość, która nie jest 1 lub 0). Jednak C# zezwala na to od 1.0 bez ostrzeżenia. Dopasowywanie wzorców jest po prostu zgodne z tym zachowaniem tutaj.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-13 22:35:10
Zestawiam tutaj wiele komentarzy na Twitterze - to dla mnie nowość i mam nadzieję, że jaredpar wskoczy z bardziej wyczerpującą odpowiedzią, ale krótka wersja, Jak to Rozumiem: {]}
case string s:
Jest interpretowane jako if(someString is string) { s = (string)someString; ...
lub if((s = (someString as string)) != null) { ... }
- z których każda wymaga testu null
- który w Twoim przypadku nie jest udany; odwrotnie:
case var o:
Gdzie kompilator rozwiązuje o
jako string
jest po prostu o = (string)someString; ...
- no null
test, pomimo faktu, że wygląda podobnie na surface, tylko z kompilatorem podającym Typ.
Wreszcie:
default:
Tutaj nie można dotrzeć , ponieważ powyższy przypadek łapie wszystko. Może to być błąd kompilatora, ponieważ nie emitował ostrzeżenia o nieosiągalnym kodzie.
Zgadzam się, że to jest Bardzo subtelne i niuansowe, i mylące. Ale najwyraźniej scenariusz case var o
ma zastosowania z propagacją null (o?.Length ?? 0
itd.). Zgadzam się, że to dziwne, że to działa tak Bardzo inaczej między var o
i string s
, Ale To właśnie robi obecnie kompilator.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-13 22:32:07
To dlatego, że case <Type>
pasuje do typudynamic (run-time), a nie do typu statycznego (compile-time). null
nie ma typu dynamicznego, więc nie może dopasować się do string
. var
jest tylko alternatywą.
(postowanie, bo lubię krótkie odpowiedzi.)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-14 00:38:23