Compte tenu du code suivant:
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;
}
Pourquoi l'instruction switch correspond-elle case var o
?
C'est ma compréhension qui case string s
ne correspond pas quand s == null
parce que (effectivement) (null as string) != null
évalue faux. IntelliSense sur VS Code me dit que o
c'est string
aussi. Des pensées?
Similaire à: cas de commutation C # 7 avec des vérifications nulles
o
eststring
(confirmée avec les génériques - c'est-à-direFoo(o)
oùFoo<T>(T template) => typeof(T).Name
) - c'est un cas très intéressant oùstring x
se comporte différemment quevar x
même quandx
est tapé (par le compilateur) commestring
var
dans ce contexte. Cela semble être le genre de chose que je trouverais en C ++, pas dans un langage censé conduire le programmeur "dans le gouffre du succès". Ici,var
c'est à la fois ambigu et inutile, des choses que la conception C # semble généralement s'efforcer d'éviter.switch
pourrait être imprononçable - types anonymes, etc. et ce n'est pas ambigu - le compilateur connaît clairement le type; il est juste déroutant (pour moi du moins) que lesnull
règles soient si différentes!Réponses:
Dans une
switch
instruction de correspondance de modèle utilisant uncase
pour un type explicite, il est demandé si la valeur en question est de ce type spécifique ou d'un type dérivé. C'est l'équivalent exact deis
La valeur
null
n'a pas de type et ne satisfait donc à aucune des conditions ci-dessus. Le type statique desomeString
n'entre en jeu dans aucun des deux exemples.Le
var
type bien que dans la correspondance de modèle agit comme un joker et correspondra à n'importe quelle valeur, y comprisnull
.Le
default
cas ici est un code mort. Lecase var o
correspondra à n'importe quelle valeur, nulle ou non nulle. Un cas non par défaut l'emporte toujours sur un cas par défaut et nedefault
sera donc jamais atteint. Si vous regardez l'IL, vous verrez qu'il n'est même pas émis.En un coup d'œil, il peut sembler étrange que cela compile sans aucun avertissement (m'a définitivement jeté). Mais cela correspond au comportement C # qui remonte à 1.0. Le compilateur autorise les
default
cas même lorsqu'il peut prouver de manière triviale qu'il ne sera jamais atteint. Considérez comme exemple ce qui suit:Ici
default
ne sera jamais atteint (même pour ceuxbool
qui ont une valeur qui n'est pas 1 ou 0). Pourtant, C # a permis cela depuis 1.0 sans avertissement. La correspondance de modèle est juste en ligne avec ce comportement ici.la source
var
qu'il est de typestring
alors que ce n'est vraiment pas le cas (honnêtement, je ne sais pas quel type devrait être, certes)var
dans l'exemple est calculé comme étantstring
.csc /stiffUpperLip
null
est unestring
référence valide , et toutestring
référence (y comprisnull
) peut être implicitement convertie (en préservant les références) enobject
référence, et touteobject
référence qui estnull
peut être convertie avec succès (explicite) vers tout autre type, toujours en coursnull
. Pas vraiment la même chose en termes de système de type compilateur.Je rassemble plusieurs commentaires Twitter ici - c'est en fait nouveau pour moi, et j'espère que jaredpar interviendra avec une réponse plus complète, mais; version courte telle que je la comprends:
est interprété comme
if(someString is string) { s = (string)someString; ...
ouif((s = (someString as string)) != null) { ... }
- ce qui implique unnull
test - qui a échoué dans votre cas; inversement:où le compilateur résout
o
tel quelstring
simplemento = (string)someString; ...
- pas denull
test, malgré le fait qu'il semble similaire en surface, juste avec le compilateur fournissant le type.enfin:
ici ne peut pas être atteint , car le cas ci-dessus attrape tout. Cela peut être un bogue du compilateur dans la mesure où il n'a pas émis d'avertissement de code inaccessible.
Je conviens que c'est très subtil et nuancé et déroutant. Mais apparemment, le
case var o
scénario a des utilisations avec une propagation nulle (o?.Length ?? 0
etc.). Je suis d' accord qu'il est étrange que cela fonctionne si très différemment entrevar o
etstring s
, mais il est ce que le compilateur fait actuellement.la source
C'est parce que
case <Type>
correspond au type dynamique (à l'exécution) et non au type statique (à la compilation).null
n'a pas de type dynamique, il ne peut donc pas correspondrestring
.var
est juste la solution de secours.(Publier parce que j'aime les réponses courtes.)
la source