91 votes

interrupteur avec var/null comportement étrange

Étant donné le 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 de commutation correspond-elle à case var o ?

Je crois savoir que case string s ne correspond pas lorsque s == null parce que (effectivement) (null as string) != null a pour valeur false. IntelliSense sur VS Code me dit que o es un string également. Des idées ?


Similaire à : C# 7 switch case avec contrôles de nullité

69voto

JaredPar Points 333733

À l'intérieur d'un modèle de correspondance switch en utilisant un case pour un type explicite, c'est demander si la valeur en question est de ce type spécifique, ou d'un type dérivé. C'est l'équivalent exact de is

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

La valeur null n'a pas de type et ne satisfait donc pas à l'une des conditions ci-dessus. Le type statique de someString n'entre pas en jeu dans les deux exemples.

Le site var dans le filtrage de motifs, agit comme un caractère de remplacement et correspondra à n'importe quelle valeur, notamment null .

Le site default Ce cas est un code mort. Le site case 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, donc default ne sera jamais touché. Si vous regardez l'IL, vous verrez qu'il n'est même pas émis.

Au premier coup d'œil, il peut sembler étrange que cela compile sans aucun avertissement (cela m'a certainement déconcerté). Mais cela correspond au comportement du C# qui remonte à la version 1.0. Le compilateur permet default même lorsqu'il peut trivialement prouver qu'il ne sera jamais touché. Considérons par exemple ce qui suit :

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

Ici default ne sera jamais atteint (même pour bool qui ont une valeur qui n'est pas 1 ou 0). Pourtant, C# a permis cela depuis la version 1.0 sans avertissement. La correspondance de motifs s'aligne simplement sur ce comportement ici.

22voto

Marc Gravell Points 482669

Je rassemble ici plusieurs commentaires sur Twitter - 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 :

case string s:

est interprété comme if(someString is string) { s = (string)someString; ... o if((s = (someString as string)) != null) { ... } - dont l'une ou l'autre implique un null qui a échoué dans votre cas ; inversement :

case var o:

où le compilateur résout o comme string est simplement o = (string)someString; ... - non null test, malgré le fait que cela semble similaire en surface, juste avec le compilateur fournissant le type.

enfin :

default:

aquí ne peut être atteint parce que l'affaire ci-dessus englobe tout. Il s'agit peut-être d'un bogue du compilateur dans la mesure où il n'a pas émis d'avertissement de code inaccessible.

Je suis d'accord que c'est muy subtile et nuancée, et déroutante. Mais apparemment, le case var o Le scénario a des utilisations avec la propagation nulle ( o?.Length ?? 0 etc). Je suis d'accord pour dire qu'il est étrange que cela fonctionne ainsi. muy différemment entre var o y string s mais c'est ce que le compilateur fait actuellement.

14voto

Mehrdad Points 70493

C'est parce que case <Type> correspond à la dynamique (temps d'exécution), et non le type statique (temps de compilation). null n'a pas de type dynamique, il ne peut donc pas être comparé à string . var n'est qu'une solution de repli.

(Posting parce que j'aime les réponses courtes).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X