c# variables scope

c# - La variable declarada en for-loop es una variable local?



variables scope (9)

He estado usando C # durante bastante tiempo pero nunca me di cuenta de lo siguiente:

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 }

Entonces, ¿por qué no puedo usar el valor de ''i'' fuera del bloque for si no me permite declarar una variable con este nombre?

Pensé que la variable de iterador utilizada por un for-loop es válida solo en su alcance.


Además de la respuesta de J.Kommer (+1 por cierto). Esto está en el estándar para el alcance NET:

bloque Si declara una variable dentro de una construcción de bloque, como una instrucción If, el alcance de esa variable es solo hasta el final del bloque. La duración es hasta que el procedimiento finaliza.

Procedimiento Si declara una variable dentro de un procedimiento, pero fuera de cualquier instrucción If, el alcance es hasta la función End Sub o End. La duración de la variable es hasta que finaliza el procedimiento.

Por lo tanto, la int i decalared dentro del encabezado for del bucle estará en el alcance solo durante el bloque for loop, PERO su vida útil dura hasta que se complete el código Main() .


Hay una manera de declarar y usar i dentro del método después del ciclo:

static void Main() { for (int i = 0; i < 5; i++) { } { int i = 4; int A = i; } }

Puedes hacer esto en Java (puede que se origine desde C, no estoy seguro). Por supuesto, es un poco complicado por el bien de un nombre de variable.


La forma más fácil de pensar sobre esto es mover la declaración externa de I a encima del ciclo. Debería ser obvio entonces.

Es el mismo ámbito de cualquier manera, por lo tanto no se puede hacer.


La razón por la que no está permitido definir una variable con el mismo nombre tanto para for-loop como fuera de for-loop es porque las variables en el ámbito externo son válidas en el ámbito interno. Lo que significa que habría dos variables ''i'' dentro del bucle for si esto estuviera permitido.

Ver: ámbitos de MSDN

Específicamente:

El alcance de una variable local declarada en una declaración de variable local (Sección 8.5.1) es el bloque en el que se produce la declaración.

y

El alcance de una variable local declarada en un inicializador para una instrucción for (Sección 8.8.3) es for-initializer, for-condition, for-iterator y la instrucción contenida de la instrucción for.

Y también: declaraciones de variables locales (Sección 8.5.1 de la especificación C #)

Específicamente:

El alcance de una variable local declarada en una declaración de variable local es el bloque en el que se produce la declaración. Es un error referirse a una variable local en una posición textual que precede al declarador de variable local de la variable local. Dentro del alcance de una variable local, es un error en tiempo de compilación declarar otra variable local o constante con el mismo nombre.

(Énfasis mío)

Lo que significa que el alcance de la i dentro de su for-loop, es el for-loop. Mientras que el alcance de la i fuera de su bucle for es el método principal completo más el for-loop. Lo que significa que tendría dos ocurrencias de i dentro del ciclo que no es válido de acuerdo con lo anterior.

La razón por la que no está permitido hacer int A = i; es porque int i solo tiene un alcance para su uso dentro del ciclo for . Por lo tanto, ya no es accesible fuera del ciclo for .

Como puede ver, estos dos problemas son el resultado del alcance; el primer problema ( int i = 4; ) resultaría en dos variables dentro del alcance del bucle for . Considerando que int A = i; daría como resultado el acceso a una variable que está fuera del alcance.

Lo que podría hacer en su lugar es declarar que tengo un alcance para todo el método, y luego usarlo tanto en el método como en el alcance for-loop. Esto evitará romper cualquiera de las reglas.

public static void Main() { int i; for (i = 0; i < 5; i++) { } // ''i'' is only declared in the method scope now, // no longer in the child scope -> valid. i = 4; // ''i'' is declared in the method''s scope -> valid. int A = i; }

EDITAR :

El compilador de C # podría, por supuesto, modificarse para permitir que este código se compile de manera bastante válida. Después de todo esto es válido:

for (int i = 0; i < 5; i++) { Console.WriteLine(i); } for (int i = 5; i > 0; i--) { Console.WriteLine(i); }

Pero, ¿sería realmente beneficioso para la legibilidad y mantenimiento de su código poder escribir código como:

public static void Main() { int i = 4; for (int i = 0; i < 5; i++) { Console.WriteLine(i); } for (int i = 5; i > 0; i--) { Console.WriteLine(i); } Console.WriteLine(i); }

Piensa en el potencial de errores aquí, ¿imprimo el último 0 o 4? Ahora bien, este es un ejemplo muy pequeño, que es bastante fácil de seguir y rastrear, pero definitivamente es mucho menos fácil de mantener y legible que haber declarado el nombre externo i con un nombre diferente.

NÓTESE BIEN:

Tenga en cuenta que las reglas de alcance de C # difieren de las reglas de alcance de C ++ . En C ++, las variables solo están en el alcance desde donde se declaran hasta el final del bloque. Lo que haría que tu código sea una construcción válida en C ++.


La respuesta de J.Kommer es correcta: brevemente, es ilegal declarar una variable local en un espacio de declaración de variable local que se superpone a otro espacio de declaración de variable local que tiene un local del mismo nombre.

Hay una regla adicional de C # que también se viola aquí. La regla adicional es que es ilegal que se use un nombre simple para referirse a dos entidades diferentes dentro de dos espacios de declaración de variables locales superpuestos diferentes. Entonces, no solo es ilegal su ejemplo, esto también es ilegal:

class C { int x; void M() { int y = x; if(whatever) { int x = 123;

Porque ahora el nombre simple "x" se ha usado dentro del espacio de declaración de variable local de "y" para significar dos cosas diferentes - "this.x" y la "x" local.

Consulte http://blogs.msdn.com/b/ericlippert/archive/tags/simple+names/ para obtener más análisis de estos problemas.


La respuesta de Kommer es técnicamente correcta. Permítanme parafrasearlo con una vívida metáfora de pantalla ciega.

Hay una pantalla ciega unidireccional entre el bloque exterior y el bloque externo circundante, de modo que el código que se encuentra dentro del bloque puede ver el código externo pero el código en el bloque externo no puede ver el código dentro.

Como el código externo no puede ver el interior, no puede usar nada declarado dentro. Pero dado que el código en el bloque for puede ver tanto dentro como fuera, una variable declarada en ambos lugares no se puede usar inequívocamente por nombre.

Entonces, o no lo ves, o C #!


Mírelo de la misma manera que si pudiera declarar un int en un bloque de using :

using (int i = 0) { // i is in scope here } // here, i is out of scope

Sin embargo, dado que int no implementa IDisposable , esto no se puede hacer. Sin embargo, puede ayudar a alguien a visualizar cómo se ubica una variable int en un ámbito privado.

Otra forma sería decir,

if (true) { int i = 0; // i is in scope here } // here, i is out of scope

Espero que esto ayude a visualizar lo que está pasando.

Me gusta mucho esta característica, ya que declarar el int desde adentro del ciclo for mantiene el código bueno y ajustado.


Si hubiera declarado i antes de su bucle for , ¿cree que aún debería ser válido declararlo dentro del bucle?

No, porque entonces el alcance de los dos se superpondría.

En cuanto a no poder hacer int A=i; , bueno, eso es simplemente porque solo existe en el ciclo for , como debería ser.


También las reglas de C # son muchas veces innecesarias en términos de programación estrictamente, pero están ahí para mantener su código limpio y legible.

por ejemplo, podrían haberlo hecho de modo que si lo defines después del ciclo está bien, sin embargo, alguien que lea tu código y haya perdido la línea de definición puede pensar que tiene que ver con la variable del ciclo.