9
votes

Déclaration de cas Espace de déclaration de niveau de bloc en C #

Y a-t-il une raison pour laquelle il manquait qu'un bloc dans une déclaration de cas n'est pas considéré comme un espace de déclaration de niveau de blocage?

Je continue à obtenir une erreur (la variable a déjà été déclarée) lorsque j'essaie < Pré> xxx

mais je peux faire xxx

si c # autorisé tomber à travers des déclarations, cela aurait un sens, mais ça ne peut pas, et je peux 't penser à un scénario où vous pouvez déclarer une variable dans une déclaration de cas et l'utiliser en dehors de ce bloc.


3 commentaires

Dupliquer: Stackoverflow.com/Questtions/864153/...


Et une autre: Stackoverflow.com/Questtions/222601 / ...


L'édition clarifie ce que vous recherchez. Cela dit, il y a une chute très limitée à travers des déclarations de cas C #, mais elle ne s'applique que lorsque les cas que vous souhaitez n'échouer n'ont aucune déclaration.


6 Réponses :


4
votes

Vous pouvez également faire:

case x:
  {var someVariable = 42;}
break;
case y: 
   {var someVariable = 40;}
break;


2 commentaires

C'est faux, causera docs.microsoft.com/en-us/dotnet/cshaarp/misc/..... , i ceci vote


@Raidencore Je ne pense pas que cette erreur soit liée du tout. C'est la même chose que si vous essayiez de déclarer variables à l'intérieur du corps de si () et cette variable existait déjà. Comme int a; Si (vrai) {Char A; } .



2
votes

Parce que les cas ne sont pas des blocs, il n'y a pas d'accolades frisées dénotant la portée. Les cas sont, faute d'un meilleur mot, comme des étiquettes.

Vous ferez mieux de déclarer la variable en dehors de la commutation () et de l'utiliser par la suite. Bien sûr, dans ce scénario, vous ne pourrez pas utiliser le mot-clé var , car le compilateur ne saura pas quel type d'initialisation.


4 commentaires

Ma question est pourquoi n'est-il pas considéré comme un bloc. Pourquoi devez-vous vous forcer à être un?


Les blocs de portée ne sont jamais automatiques en C #. Ils n'existent pas par défaut. Les blocs de portée sont toujours définis avec des accolades bouclées. Vous remarquerez peut-être que la portée prend effet pour, foreach, si, etc., déclarations - lorsque vous utilisez des accolades bouclées pour désigner le bloc de portée. Avec les déclarations susmentionnées, si vous omettez les bretelles frisées, elles fonctionnent uniquement sur la ligne très suivante - car il n'y a pas de portée sans définition du début et de la fin via des accolades. Étant donné que l'étui ne nécessite pas d'accolades, sauf si vous décidez de les insérer, les instructions de cas utilisent la portée la plus proche, qui est la déclaration de commutation.


Ouais ça a du sens maintenant. Je n'ai pas pensé à eux comme étiquettes, et c'était curieux pourquoi vous devriez avoir une {} pour forcer la portée, lorsque la déclaration de pause pourrait être utilisée pour déterminer la fin de la déclaration de cas. Toujours avoir à forcer la portée a du sens car cela constituerait une pause dans la structure générale de la langue également.


John Rudy, votre analyse, bien que plausible, n'est pas réellement correcte du tout. Ce n'est tout simplement pas le cas que les scopes sont toujours délimités par des accolades bouclées en C #. La boucle de Foreach introduit une nouvelle portée, même si le corps n'a pas d'accolades. La portée est extrêmement soigneusement définie dans la spécification C #; Je vous encourage à la lire à fond si vous souhaitez corriger votre compréhension de ce que les règles sont exactement pour introduire de nouvelles étendues dans C #.



-1
votes

Vous pouvez simplement déclarer la variable en dehors de la portée de l'instruction de commutation.

var someVariable;

switch();
case x:   
someVariable = 42;
break; 
case y:     
someVariable = 40;
break;


1 commentaires

Vous ne pouvez pas faire cela, car le compilateur ne sait pas quel type quelqueevariable est. Vous devez faire au moins var soyvariable = par défaut (int); . Vous avez aussi une faute de frappe dans le code, il y a ; après le commutateur () .



8
votes

ah - vous n'avez pas de baisse, mais vous pouvez utiliser goto pour sauter à un autre bloc de cas marqué. Par conséquent, les blocs doivent être dans la même portée.


6 commentaires

+1 pour souligner la raison pragmatique pour laquelle cette notation n'est pas possible.


+1 Parce que je serais soupçonné, mais jamais testé et je ne connaissais pas avec 100% de certitude, que Goto fonctionnerait avec des étiquettes de cas. (Cimentation de mon assertion Wishy-Washy dans ma propre réponse que les étiquettes de cas sont en effet des étiquettes. :))


Voici un exemple sur mon blog (périphérique de Duff en C #) HackersBasement.com/?p=31


Je ne suis pas sûr de suivre votre logique. Dis-tu que la raison pour laquelle les blocs de cas n'introduisent pas une portée est de sorte que le commutateur (x) {cas 1: int y = 123; goto cas 2; Cas 2: Y = 456; Pause; } fonctionne sans avoir à redéclaré Y?


La raison pour laquelle je demande est parce que si c'est votre argument, votre logique est défectueuse. Les règles d'affectation définitives garantiraient que vous ne pouviez pas réussir les informations d'une "portée" à la prochaine via "goto".


Ou peut-être que vous faites l'argument selon lequel les étiquettes doivent être dans une portée tout au long du bloc, et les sections ne peuvent donc pas définir leurs propres étendues? Cet argument est également défectueux; Scopes Nest. Les étiquettes dans la portée du bloc auraient également une portée dans les cas. (Comme ils sont aujourd'hui; si vous définissez vos propres blocs explicitement, vous verrez que vous pouvez "goto cas" d'entre eux.)



38
votes

Mise à jour: Cette question a été utilisée comme source d'inspiration pour ce blog. Voir cela pour plus de détails.

http://ericlippert.com/2009 / 08/13 / Quatre-commutateurs-Odddités /

Merci pour la question intéressante.


Il y a un certain nombre de confusions et de fausses déclarations dans le Diverses autres réponses, dont aucune ne explique réellement pourquoi cela est illégal. Je vais essayer d'être définitif.

Tout d'abord, pour être strictement correct, "Scope" est le mauvais mot à utiliser pour décrire le problème. Par coïncidence, j'ai écrit un article de blog la semaine dernière à propos de cette utilisation erronée exacte de "Portée"; Cela sera publié après ma série sur des blocs Itératrice, qui courront tout au long de juillet.

Le terme correct à utiliser est " espace de déclaration ". Un espace de déclaration est une région de code dans lequel aucune deux choses différentes ne peut être déclarée avoir le même nom . Le scénario décrit ici est symptomatique du fait que A commutateur section ne définit pas un espace de déclaration, bien qu'un commutateur block fait. depuis la fonction Deux déclarations sont dans le même espace de déclaration et ont le même nom, ils sont illégaux.

(oui, le bloc de commutation aussi définit une portée, mais ce fait n'est pas pertinent pour la question parce que la question concerne la légalité d'une déclaration , pas la sémantique d'une recherche d'identifiant .)

une question raisonnable est "Pourquoi n'est-ce pas légal?" Une réponse raisonnable est "Eh bien, pourquoi devrait-elle être"? Vous pouvez avoir une des deux manières. Soit ceci est légal: xxx

ou ceci est légal: xxx

mais vous ne pouvez pas l'avoir les deux manières. Les concepteurs de C # ont choisi la deuxième manière comme semblant être le moyen plus naturel de le faire.

Cette décision a été prise le 7 juillet 1999, il y a dix ans il y a dix ans. Les commentaires dans les notes de ce jour sont extrêmement brefs, il suffit d'indiquer " un cas de commutation ne crée pas sa propre espace de déclaration ", puis donnant un certain code qui montre ce qui fonctionne et ce qui ne fait pas.

Pour en savoir plus sur ce qui se trouvait dans les esprits des designers ce jour-là, je devrais renoncer à beaucoup de gens sur ce qu'ils pensaient il y a dix ans - et les bugs sur ce qui est finalement une question triviale; Je ne vais pas faire ça.

En bref, il n'y a pas en particulier la raison convaincante de choisir un moyen ou l'autre; Les deux ont des mérites. L'équipe de conception linguistique a choisi une manière parce qu'elles devaient en choisir un; Celui qu'ils ont choisi me semblent raisonnables.


4 commentaires

Merci pour la réponse. Vraiment ma question découle du fait que j'étais curieux si je me manquais quelque chose de plus profond, comme "Vous ne pouvez pas le faire de cette façon à cause de x." L'idée de "nous avons dû prendre une décision et c'était-ce", semble être une réponse parfaitement valide et peut accepter qu'il s'agisse de prendre une décision.


La manière dont les concepteurs de langue ont choisi de le définir, vous pouvez toujours créer un nouvel espace de déclaration en se précipitant dans les déclarations de cas pour obtenir le comportement 1. Si vous allez à l'origine de comportement 1, il n'ya aucun moyen de se rendre au comportement 2.


Ensuite, var est venu. Ajouter tuple au mélange et vous avez un problème. Un résultat malheureux d'une décision commise il y a longtemps, on n'aurait pas pu prévoir cependant.


20 ans plus tard, espérant toujours qu'à un moment donné à l'avenir, une personne de l'équipe d'origine éclairera une lumière sur la décision.



1
votes

à partir de C # 8.0 Vous pouvez maintenant faire cela avec Switch Expressions

Vous utilisez l'expression de commutation pour évaluer une seule expression d'une liste d'expressions candidates basées sur une correspondance de modèle avec une expression d'entrée xxx


0 commentaires