Gegeben den folgenden Code:
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;
}
Warum stimmt die switch-Anweisung überein case var o
?
Es ist mein Verständnis, case string s
das nicht übereinstimmt, wenn, s == null
weil (effektiv) (null as string) != null
als falsch bewertet. IntelliSense auf VS Code sagt mir, dass dies auch ein o
ist string
. Irgendwelche Gedanken?
Ähnlich wie: C # 7-Schalterfall mit Nullprüfungen
o
siestring
(mit Generika bestätigt - dhFoo(o)
woFoo<T>(T template) => typeof(T).Name
) - es ist ein sehr interessanter Fall,string x
verhält sich anders alsvar x
selbst wennx
eingegeben wird (durch den Compiler) alsstring
var
in diesem Zusammenhang überhaupt zuzulassen . Das scheint sicher die Art von Dingen zu sein, die ich in C ++ finden würde, nicht in einer Sprache, die den Programmierer "in die Grube des Erfolgs" führen soll. Hiervar
ist sowohl mehrdeutig als auch nutzlos, Dinge, die C # -Design normalerweise zu vermeiden scheint.switch
könnte unaussprechlich sein - anonyme Typen usw.; und es ist nicht mehrdeutig - der Compiler kennt den Typ genau; Es ist nur verwirrend (zumindest für mich), dass dienull
Regeln so unterschiedlich sind!Antworten:
In einer Mustervergleichsanweisung
switch
mit acase
für einen expliziten Typ wird gefragt, ob der betreffende Wert von diesem bestimmten Typ oder einem abgeleiteten Typ ist. Es ist das genaue Äquivalent vonis
Der Wert
null
hat keinen Typ und erfüllt daher keine der oben genannten Bedingungen. Der statische Typ vonsomeString
kommt in beiden Beispielen nicht ins Spiel.Der
var
Typ beim Mustervergleich fungiert jedoch als Platzhalter und entspricht jedem Wert, einschließlichnull
.Der
default
Fall hier ist toter Code. Das entsprichtcase var o
jedem Wert, null oder nicht null. Ein nicht standardmäßiger Fall gewinnt immer über einen standardmäßigen Fall unddefault
wird daher niemals getroffen. Wenn Sie sich die IL ansehen, werden Sie sehen, dass sie nicht einmal ausgestrahlt wird.Auf den ersten Blick mag es seltsam erscheinen, dass dies ohne Vorwarnung kompiliert wird (hat mich definitiv abgeworfen). Dies stimmt jedoch mit dem C # -Verhalten überein, das auf 1.0 zurückgeht. Der Compiler erlaubt
default
Fälle, auch wenn er trivial beweisen kann, dass er niemals getroffen wird. Betrachten Sie als Beispiel Folgendes:Hier
default
wird niemals getroffen (auchbool
wenn der Wert nicht 1 oder 0 ist). C # hat dies jedoch seit 1.0 ohne Vorwarnung zugelassen. Der Mustervergleich entspricht hier nur diesem Verhalten.quelle
var
, dass er vom Typ ist,string
wenn er wirklich nicht ist (ehrlich gesagt nicht sicher, welcher Typ zugegebenermaßen sein soll)var
im Beispiel wird berechnetstring
.csc /stiffUpperLip
null
eine gültigestring
Referenz ist, und jedestring
Referenz (einschließlichnull
) kann implizit in eineobject
Referenz umgewandelt (referenzerhaltend) werden , und jedeobject
Referenz,null
die erfolgreich auf einen anderen Typ übertragen werden kann (explizit), ist noch vorhandennull
. Nicht wirklich dasselbe in Bezug auf das Compilertypsystem.Ich stelle hier mehrere Twitter-Kommentare zusammen - das ist eigentlich neu für mich und ich hoffe, dass Jaredpar mit einer umfassenderen Antwort einspringt, aber; Kurzfassung, wie ich sie verstehe:
wird interpretiert als
if(someString is string) { s = (string)someString; ...
oderif((s = (someString as string)) != null) { ... }
- was einennull
Test beinhaltet - was in Ihrem Fall fehlgeschlagen ist; umgekehrt:wo die Compiler Entschlüsse
o
alsstring
einfach isto = (string)someString; ...
- keinnull
Test, trotz der Tatsache , dass es auf der Oberfläche ähnlich sieht, nur mit dem Compiler die Art zu schaffen.endlich:
hier kann nicht erreicht werden , weil der obige Fall alles fängt. Dies kann ein Compiler-Fehler sein, da keine nicht erreichbare Code-Warnung ausgegeben wurde.
Ich stimme zu, dass dies sehr subtil und nuanciert und verwirrend ist. Aber anscheinend hat das
case var o
Szenario Verwendung mit Null-Weitergabe (o?.Length ?? 0
usw.). Ich bin damit einverstanden , dass es seltsam ist , dass das funktioniert so sehr unterschiedlich zwischenvar o
undstring s
, aber es ist das, was der Compiler zur Zeit der Fall ist.quelle
Dies liegt daran, dass
case <Type>
Übereinstimmungen mit dem dynamischen Typ (Laufzeit) und nicht mit dem statischen Typ (Kompilierungszeit) übereinstimmen.null
hat keinen dynamischen Typ, kann also nicht mithaltenstring
.var
ist nur der Fallback.(Posting, weil ich kurze Antworten mag.)
quelle