J'utilise C # depuis assez longtemps mais je n'ai jamais réalisé ce qui suit:
public static void Main()
{
for (int i = 0; i < 5; i++)
{
}
int i = 4; //cannot declare as 'i' is declared in child scope
int A = i; //cannot assign as 'i' does not exist in this context
}
Alors pourquoi ne puis-je pas utiliser la valeur de 'i' en dehors du bloc for si cela ne me permet pas de déclarer une variable avec ce nom?
Je pensais que la variable d'itérateur utilisée par une boucle for n'est valide que dans sa portée.
int i, A; for(int i = 0; i < 5; i++){ } i=4; A=i
Réponses:
La raison pour laquelle vous n'êtes pas autorisé à définir une variable avec le même nom à la fois dans la boucle for et en dehors de la boucle for est que les variables de la portée externe sont valides dans la portée interne. Cela signifie qu'il y aurait deux variables «i» dans la boucle for si cela était autorisé.
Voir: Étendues MSDN
Plus précisément:
et
Et aussi: Déclarations de variables locales (Section 8.5.1 de la spécification C #)
Plus précisément:
(Soulignez le mien.)
Ce qui signifie que la portée de l'
i
intérieur de votre boucle for est la boucle for. Alors que la portée de l'i
extérieur de votre boucle for est la méthode principale entière plus la boucle for. Cela signifie que vous auriez deux occurrencesi
à l'intérieur de la boucle qui ne sont pas valides selon ce qui précède.La raison pour laquelle vous n'êtes pas autorisé à le faire
int A = i;
est que son utilisationint i
est uniquement réservée à lafor
boucle. Il n'est donc plus accessible en dehors de lafor
boucle.Comme vous pouvez le voir, ces deux problèmes sont le résultat de la portée; le premier problème (
int i = 4;
) entraînerait deuxi
variables dans lafor
portée de la boucle. Alors que celaint A = i;
donnerait accès à une variable hors de portée.Ce que vous pouvez faire à la place, c'est déclarer
i
être étendu à la méthode entière, puis l'utiliser à la fois dans la méthode et dans la portée de la boucle for. Cela évitera d'enfreindre l'une ou l'autre règle.MODIFIER :
Le compilateur C # pourrait bien sûr être modifié pour permettre à ce code de se compiler de manière tout à fait valide. Après tout cela est valable:
Mais serait-il vraiment bénéfique pour la lisibilité et la maintenabilité de votre code de pouvoir écrire du code tel que:
Pensez au potentiel d'erreur ici, est-ce que le dernier
i
affiche 0 ou 4? Maintenant, c'est un tout petit exemple, qui est assez facile à suivre et à suivre, mais il est certainement beaucoup moins maintenable et lisible que d'avoir déclaré l'extérieuri
sous un nom différent.NB:
Veuillez noter que les règles de portée de C # diffèrent des règles de portée de C ++ . En C ++, les variables sont uniquement dans la portée de l'endroit où elles sont déclarées jusqu'à la fin du bloc. Ce qui ferait de votre code une construction valide en C ++.
la source
i
variable interne ; cela me semble plus évident.i
définition externe était déplacée avant la boucle for, lai
définition interne serait marquée comme invalide.La réponse de J.Kommer est correcte: brièvement, il est illégal pour une variable locale d'être déclarée dans un espace de déclaration de variable locale qui chevauche un autre espace de déclaration de variable locale qui a un local du même nom.
Il existe également une règle supplémentaire de C # qui est violée ici. La règle supplémentaire est qu'il est illégal pour un nom simple d'être utilisé pour faire référence à deux entités différentes à l'intérieur de deux espaces de déclaration de variable locale se chevauchant différents. Donc non seulement votre exemple est illégal, mais c'est aussi illégal:
Parce que maintenant, le nom simple "x" a été utilisé dans l'espace de déclaration des variables locales de "y" pour signifier deux choses différentes - "this.x" et le "x" local.
Voir http://blogs.msdn.com/b/ericlippert/archive/tags/simple+names/ pour une analyse plus approfondie de ces problèmes.
la source
int y = this.x;
this.x
n'est pas un simple nom .Il existe un moyen de déclarer et d'utiliser
i
à l'intérieur de la méthode après la boucle:Vous pouvez le faire en Java (cela peut provenir de C, je ne suis pas sûr). C'est bien sûr un peu brouillon pour le nom d'une variable.
la source
Si vous aviez déclaré
i
avant votrefor
boucle, pensez-vous qu'il devrait toujours être valide de le déclarer à l'intérieur de la boucle?Non, car alors la portée des deux se chevaucherait.
Quant à ne pas pouvoir le faire
int A=i;
, eh bien c'est tout simplement parce qu'ili
n'existe que dans lafor
boucle, comme il se doit.la source
En plus de la réponse de J.Kommer (+1 btw). Il y a ceci dans la norme pour la portée NET:
Ainsi, l'int i décalé dans l'en-tête de la boucle for ne sera dans la portée que pendant le bloc de la boucle for, MAIS sa durée de vie dure jusqu'à ce que le
Main()
code se termine.la source
La façon la plus simple d'y penser est de déplacer la déclaration externe de I au-dessus de la boucle. Cela devrait alors devenir évident.
C'est la même portée de toute façon, donc ne peut pas être fait.
la source
De plus, les règles de C # sont souvent inutiles en termes de programmation, mais sont là pour garder votre code propre et lisible.
par exemple, ils auraient pu faire en sorte que si vous le définissez après la boucle, alors tout va bien, mais quelqu'un qui lit votre code et a raté la ligne de définition peut penser que cela a à voir avec la variable de la boucle.
la source
La réponse de Kommer est techniquement correcte. Permettez-moi de le paraphraser avec une métaphore éclatante de l'écran aveugle.
Il y a un écran aveugle unidirectionnel entre le bloc for et le bloc extérieur englobant de sorte que le code de l'intérieur du bloc for puisse voir le code extérieur mais le code du bloc extérieur ne peut pas voir le code à l'intérieur.
Puisque le code externe ne peut pas voir à l'intérieur, il ne peut pas utiliser quoi que ce soit déclaré à l'intérieur. Mais comme le code dans le bloc for peut voir à la fois l'intérieur et l'extérieur, une variable déclarée aux deux endroits ne peut pas être utilisée sans ambiguïté par son nom.
Donc soit vous ne le voyez pas, soit vous C #!
la source
Regardez-le de la même manière que si vous pouviez déclarer un
int
dans unusing
bloc:Cependant, puisque
int
ne met pas en œuvreIDisposable
, cela ne peut pas être fait. Cela peut cependant aider quelqu'un à visualiser comment uneint
variable est placée dans une portée privée.Une autre façon serait de dire,
J'espère que cela aidera à visualiser ce qui se passe.
J'aime vraiment cette fonctionnalité, car déclarer le
int
de l'intérieur de lafor
boucle garde le code agréable et serré.la source
using
est tout à fait correcte, bien que la sémantique soit plutôt différente (c'est peut-être pourquoi il a été déclassé). Notez queif (true)
c'est redondant. Retirez-le et vous avez un bloc de portée.