12
votes

Portée variable dans les blocs de déclaration

for (int i = 0; i < 10; i++)
{
    Foo();
}
int i = 10; // error, 'i' already exists

----------------------------------------    

for (int i = 0; i < 10; i++)
{
    Foo();
}
i = 10; // error, 'i' doesn't exist
By my understanding of scope, the first example should be fine. The fact neither of them are allowed seems even more odd. Surely 'i' is either in scope or not. Is there something non-obvious about scope I don't understand which means the compiler genuinely can't resolve this? Or is just a case of nanny-state compilerism? 

0 commentaires

9 Réponses :


0
votes

ou est juste un cas d'état nounou COMPILERISME?

exactement ça. Il n'a aucun sens dans la réutilisation des noms variables dans la même méthode. C'est juste une source d'erreurs et rien de plus.


1 commentaires

Le problème n'est pas en réutilisant des noms de variables; Il est parfaitement légal de réutiliser un nom de variable plusieurs fois dans une méthode. Il n'est pas légal d'utiliser le même nom simple pour faire référence à deux choses différentes dans un espace de déclaration de variable local particulier.



1
votes

Dans le premier exemple, la déclaration de I à l'extérieur de la boucle fait de la variable locale de la fonction. En conséquence, il s'agit d'une erreur d'avoir un autre nom de variable que j'ai déclaré dans n'importe quel bloc de cette fonction.

La seconde, je n'approuve que pendant la boucle. En dehors de la boucle, je ne peux plus être accessible.

Vous avez donc vu les erreurs, mais il n'y a rien de mal à faire ce xxx

parce que La portée de I est limitée dans chaque bloc.


0 commentaires

11
votes

C'est parce que l'espace de déclaration définit i au niveau de la méthode. La variable i est hors de portée à la fin de la boucle, mais vous ne pouvez toujours pas redéclaré i , car i était déjà défini dans cette méthode.

Scope VS Space de déclaration:

http://csharpfeeds.com/post/11730/Whats_The_Difference_Part_Two_Scope_vs_Declaration_Space_vs_Lifetime.aspx < / p>

Vous voudrez jeter un coup d'œil à la réponse d'Eric Lippert (qui par défaut est toujours juste en ce qui concerne les questions telles que celles-ci).

http://blogs.msdn.com/ericlippert/archive/2009/08/03/What-s-the-freference-Part-two-scope-vs-SPACE- vs-lifetime.aspx

Voici un commentaire d'Eric sur le poste mentionné ci-dessus que je pense parler de pourquoi ils ont fait ce qu'ils ont fait:

Regardez-le de cette façon. Il devrait toujours être légal pour déplacer la déclaration d'un variable dans le code source si longtemps Comme vous le gardez dans le même bloc, droite? Si nous l'avons fait comme ça suggère, alors ce serait parfois légal et parfois illégal! Mais La chose que nous voulons vraiment éviter est Que se passe-t-il en C ++ - en C ++, déplaçant parfois une variable Déclaration augmente effectivement la Reliures d'autres noms simples!


12 commentaires

Mais alors pourquoi pouvez-vous définir i dans la portée d'une autre boucle dans la même méthode? Je pense toujours que c'est juste la bureaucratie de la part du compilateur.


@Michael: Vous pouvez le faire parce que les boucles sont des étendues frères. Il n'y a pas de collision définissant des variables nommées à l'identique dans des étendues frontalières car elles sont hors de portée de l'autre.


@Zach: Cependant, le premier bloc de la question initiale montre exactement que: il n'y a pas de collision. Mais cela ne compilera toujours pas.


Wow, je n'avais aucune idée de cela existait. Je vais m'assurer d'ajouter ceci à ma liste de raisons que je déteste c #


Aucune raison de le haïr pour ça. Il se comporte exactement comme il devrait être: vous empêcher de vous tirer au pied pour des raisons qui ne valent même pas la peine de parler (réutiliser des noms variables).


@FOXfire: Le premier exemple de la question est une relation parent-enfant de portée, provoquant une collision. Les étendues frontalières sont des champs de culture qui sont tous les deux enfants de la portée des parents.


Ah bon? Je l'aime comme ça. Je ne peux pas penser à une raison de déclarer une variable avec le même nom dans la même méthode, et cela m'empêche de moi (ou de quelqu'un d'autre) de déplacer une variable autour et de causer un comportement inattendu à l'avenir.


Merci pour le shout-out. Couple de choses. Tout d'abord, c'est un meilleur article: blogs.msdn.com/ericlippert/archive/2009/11/02/... et deuxième, mieux lier à l'original plutôt que la copie; De cette façon, vous obtenez mes mises à jour et lisez les commentaires des autres: blogs.msdn.com/ericlippert /archive/2009/08/03/...


@Zach: Cette réponse (et les documents liés) indiquent le contraire: ils sont dans des espaces de déclaration différents. Cependant, en termes de portée des deux pouvant exister avec bonheur car ils sont à la fois des enfants (non-chevauchement) de la méthode. La boucle I est hors de portée à la fin de la boucle!


De toute évidence, mon commentaire ci-dessus devrait lire (juste pour corriger cela): ils sont dans le même espace de déclaration.


@Foxfire: Je pense que la question (au moins dans sa forme actuelle) concerne la portée des variables locales. Le i dans le pour est dans une portée enfant et le i écrit après la boucle dans la portée des parents de la boucle, ce qui est causant la collision. Voir ma réponse:


@meatAdor Vous trouvez une raison de détester une langue car elle applique des règles qui empêchent des bugs vraiment méchant et difficiles à compter avec pratiquement aucun inconvénient au programmeur?



0
votes

moi pense que le compilateur signifie dire que i a été déclaré au niveau de la méthode et scopé dans le cadre de la pour boucle.

Donc, dans le boîtier 1 - vous obtenez une erreur que la variable existe déjà, ce qu'elle fait

& dans le cas 2 - car la variable n'est définie que dans la boucle pour , on ne peut pas accéder à l'extérieur. boucle

Pour éviter cela, vous pouvez: xxx

mais je ne peux pas penser à un cas où vous voudriez faire cela.

hth


0 commentaires

0
votes

Vous devez faire

            int i ;
            for ( i = 0; i < 10; i++)
            {

            }
            i = 10;


0 commentaires

2
votes

oui, j'ai deuxième que le commentaire "Nanny-State Compilerisme". Ce qui est intéressant, c'est que cela va bien.

/*
 * Now there is only one meaning for index in this scope
 */
ClearEmailAddressesFor(people); // the method name works like a comment now
var index = GetIndexForSomethingElse();

/*
 * Now index has a single meaning in the scope of this method.
 */
private void ClearEmailAddressesFor(IList<Person> people)
{
    for (var index = 0; index < people.Count; index++)
    {
        people[index].Email = null;
    }
}


6 commentaires

Ce n'est pas incompatible. La règle est que le même nom simple peut ne pas être utilisé pour désigner deux choses différentes dans l'espace de déclaration variable local la plus externe dans lequel le nom simple est directement utilisé . A pour la boucle définit un espace de déclaration de variable local. Je pense que vous constaterez que cette règle est toujours appliquée dans chacun de vos exemples.


Il peut être cohérent lorsque vous analysez la langue de la spécification, mais du point de vue du consommateur, il est incompatible. Si une variable est hors de portée et ne peut pas être utilisée, il n'y a pas de bonne raison pour que je ne puisse pas être capable de créer une autre variable du même nom.


Il y a une très bonne raison . La très bonne raison est que d'utiliser le même nom simple pour faire référence à deux entités différentes dans des espaces de déclaration qui se chevauchent est déroutant et sujette de bug et devrait donc être illégal .


@ERIC Je pense que votre opinion sur ceci est aromatisée par le fait que vous êtes intimement familier avec ce qui est sous le capot. Du point de vue d'un consommateur simple, si je n'ai aucune possibilité d'accéder ou de modifier une variable, il est effectivement hors de portée. Dans ce cas, peu importe la manière dont la portée est manipulée techniquement , elle devrait être traitée par la langue comme hors de portée. Si je ne peux pas créer une variable à l'extérieur d'une boucle précédemment déclarée à l'intérieur de cette boucle (voir mon troisième exemple), alors c'est est déroutant, car la variable dans la boucle est hors contexte, sinon techniquement hors de portée.


est traité comme hors de portée. Comme je l'ai dit à plusieurs reprises, ce n'est pas un problème de portée du tout. C'est un problème de en utilisant la même séquence de lettres pour signifier deux choses différentes dans des régions qui se chevauchent du code . Arrêtez de penser à la portée; Ce n'est pas un problème de slimage en premier lieu.


Ok, alors j'ai fait un faux pas sémantique, et je m'excuse. En tant que développeur, je préférerais penser à une boucle comme un bloc de code complètement autonome. Le problème peut être résolu en composant la boucle dans une autre méthode (ce dernier est préféré de toute façon car elle favorise généralement la lisibilité). Merci pour les commentaires informatifs.




17
votes

Par ma compréhension de la portée, le premier exemple devrait aller bien. p>

Votre compréhension de la portée est bonne. Ce n'est pas une erreur de scopage. C'est une utilisation incohérente d'une erreur de nom simple. P>

int i = 10; // erreur, "je" existe déjà p> blockQuote>

ce n'est pas l'erreur qui est rapportée forte>. L'erreur rapportée est "une variable locale nommée i ne peut pas être déclarée dans cette portée car cela donnerait un sens différent à je qui est déjà utilisé dans une portée enfant pour désigner quelque chose d'autre EM>" P >

Le message d'erreur vous indique quelle est l'erreur; Lisez le message d'erreur à nouveau. Il ne dit nulle part qu'il y a un conflit entre les déclarations; Il dit que l'erreur est car cela modifie la signification du nom simple em>. L'erreur est pas forte> la redéclaration; Il est parfaitement légal d'avoir deux choses dans deux scopes différentes qui ont le même nom, même si ces scopes nichent. Qu'est-ce que pas em> légal est d'avoir un seul nom simple signifie deux choses différentes dans des espaces de déclarations variables locales imbriquées em>. p>

vous obtiendriez l'erreur "Une variable locale nommée I est déjà définie dans la présente portée" si vous avez fait quelque chose comme p> xxx pré> blockquote>

Sûrement «I» est dans la portée ou non. p> blockQuote>

sûr - mais donc quoi? Si une personne donnée est en portée ou non n'est pas pertinente. Par exemple: p> xxx pré>

parfaitement légal. L'extérieur I est dans une portée tout au long de M., il n'y a pas de problème avec le tout, déclarant un local I qui ombres la portée extérieure. Quel serait un problème est si vous avez dit P>

class C 
{
    int i;
    void M()
    {
        int x = i;
        foreach(char i in ...


0 commentaires

0
votes
class Test
{
    int i;
    static int si=9; 

    public Test()
    {
        i = 199;
    }

    static void main()
    {
        for (int i = 0; i < 10; i++)
        {
            var x = 2;
        }

        { var x = 3; }

        {    // remove outer "{ }" will generate compile error
            int si = 3; int i = 0;

             Console.WriteLine(si);
             Console.WriteLine(Test.si);
             Console.WriteLine(i);
             Console.WriteLine((new Test()).i);
        }
    }
}

0 commentaires