scope variable en bloques de instrucciones

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 

Según mi comprensión del scope, el primer ejemplo debería estar bien. El hecho de que ninguno de ellos esté permitido parece aún más extraño. Seguramente ‘yo’ está dentro del scope o no.

¿Hay algo no obvio sobre el scope que no entiendo, lo que significa que el comstackdor realmente no puede resolver esto? ¿O es solo un caso de comstackdor de estado de niñera?

Según mi comprensión del scope, el primer ejemplo debería estar bien.

Su comprensión del scope está bien. Esto no es un error de scope. Es un uso inconsistente del error de nombre simple.

int i = 10; // error, ‘yo’ ya existe

Ese no es el error que se informa . El error que se informa es “una variable local llamada i no se puede declarar en este ámbito porque daría un significado diferente a i, que ya se utiliza en un ámbito hijo para denotar algo diferente

El mensaje de error te dice cuál es el error; leer el mensaje de error nuevamente No dice en ninguna parte que haya un conflicto entre las declaraciones; dice que el error es porque eso cambia el significado del nombre simple . El error no es la restatement; es perfectamente legal tener dos cosas en dos ámbitos diferentes que tengan el mismo nombre, incluso si esos ámbitos anidan. Lo que no es legal es tener un nombre simple que signifique dos cosas diferentes en los espacios de declaraciones de variables locales nesteds .

Obtendría el error “una variable local llamada i ya está definida en este ámbito” si en cambio hiciera algo así como

 int i = 10; int i = 10; 

Seguramente ‘yo’ está dentro del scope o no.

Claro, pero ¿y qué? Si un i dado está en el scope o no es irrelevante. Por ejemplo:

 class C { int i; void M() { string i; 

Perfectamente legal. El exterior i está en el scope a lo largo de M. No hay ningún problema en absoluto al declarar un i local que sombrea el scope externo. Lo que sería un problema es si dijeras

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

Porque ahora has usado i para significar dos cosas diferentes en dos espacios de statement de variables locales nesteds: una variable de ciclo y un campo. Eso es confuso y propenso a errores, por lo que lo hacemos ilegal.

¿Hay algo no obvio sobre el scope que no entiendo, lo que significa que el comstackdor realmente no puede resolver esto?

No entiendo la pregunta. Obviamente, el comstackdor puede analizar completamente el progtwig; si el comstackdor no pudo resolver el significado de cada uso de i, ¿cómo podría informar el mensaje de error? El comstackdor puede determinar completamente que ha usado ‘i’ para significar dos cosas diferentes en el mismo espacio de statement de variable local, e informa el error en consecuencia.

Es porque el espacio de statement define i en el nivel de método. La variable i está fuera del scope al final del ciclo, pero aún no puede redeclarar i , porque ya estaba definido en ese método.

Alcance vs Espacio de statement:

http://csharpfeeds.com/post/11730/Whats_The_Difference_Part_Two_Scope_vs_Declaration_Space_vs_Lifetime.aspx

Deberías echarle un vistazo a la respuesta de Eric Lippert (quien de manera predeterminada siempre tiene razón con respecto a preguntas como estas).

http://blogs.msdn.com/ericlippert/archive/2009/08/03/what-s-the-difference-part-two-scope-vs-declaration-space-vs-lifetime.aspx

Aquí hay un comentario de Eric sobre la publicación mencionada anteriormente que creo que habla sobre por qué hicieron lo que hicieron:

Míralo de esta manera. Siempre debe ser legal mover la statement de una variable ARRIBA en el código fuente, siempre y cuando la mantenga en el mismo bloque, ¿verdad? Si lo hiciéramos de la manera que sugieres, ¡eso a veces sería legal y, a veces, ilegal! Pero lo que realmente queremos evitar es lo que sucede en C ++: en C ++, a veces mover una statement de variable realmente cambia las ataduras de otros nombres simples.

A partir de la especificación de C # en las declaraciones de variables locales :

El scope de una variable local declarada en una statement de variable local es el bloque en el que se produce la statement.

Ahora, por supuesto, no puede usar i antes de declararlo, pero el scope de la statement i es todo el bloque que lo contiene:

 { // scope starts here for (int i = 0; i < 10; i++) { Foo(); } int i = 10; } 

La variable for i está en un ámbito hijo, de ahí la colisión de nombres de variables.

Si reorganizamos la posición de la statement, la colisión se vuelve más clara:

 { int i = 10; // collision with i for (int i = 0; i < 10; i++) { Foo(); } } 

En el primer ejemplo, la statement de i fuera del ciclo hace ia variable local de la función. Como resultado, es un error tener otro nombre de variable que haya declarado dentro de cualquier bloque de esa función.

El segundo, yo solo estoy en el scope durante el ciclo. Fuera del ciclo, ya no se puede acceder.

Entonces has visto los errores, pero no hay nada de malo en hacer esto

 for (int i = 0; i < 10; i++) { // do something } foreach (Foo foo in foos) { int i = 42; // do something } 

Porque el scope de i está limitado dentro de cada bloque.

Sí, secundo el comentario del “comstackdor de estado de niñera”. Lo interesante es que esto está bien.

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

y esto está bien

 for (int i = 0; i < 10; i++) { } for (int j = 0; j < 10; j++) { var i = 12; } 

pero esto no es

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

a pesar de que puedes hacer esto

 for (int i = 0; i < 10; i++) { var k = 12; } for (int i = 0; i < 10; i++) { var k = 13; } 

Todo es un poco inconsistente.

EDITAR

Basado en el intercambio de comentarios con Eric a continuación, pensé que podría ser útil mostrar cómo trato de manejar los bucles. Intento componer bucles en su propio método siempre que sea posible. Lo hago porque promueve la legibilidad.

ANTES DE

 /* * doing two different things with the same name is unclear */ for (var index = 0; index < people.Count; index++) { people[index].Email = null; } var index = GetIndexForSomethingElse(); 

DESPUÉS

 /* * 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 people) { for (var index = 0; index < people.Count; index++) { people[index].Email = null; } } 

¿O es solo un caso de comstackdor de estado de niñera?

Exactamente eso. No tiene sentido “reutilizar” nombres de variables en el mismo método. Es solo una fuente de errores y nada más.

Me parece que el comstackdor quiere decir que i han declarado en el nivel de método y en el scope del bucle for .

Entonces, en el caso 1, se obtiene un error de que la variable ya existe, lo que hace

& en el caso 2 – dado que la variable tiene un scope solo dentro del bucle for , no se puede acceder fuera de ese bucle

Para evitar esto, podrías:

 var i = 0; for(i = 0, i < 10, i++){ } i = 10; 

pero no puedo pensar en un caso en el que quieras hacer esto.

HTH

necesitas hacer

  int i ; for ( i = 0; i < 10; i++) { } i = 10; 
 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); } } }