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 iteradora utilizada por un bucle for solo es válida en su alcance.

int i, A; for(int i = 0; i < 5; i++){ } i=4; A=iRespuestas:
La razón por la que no se le permite definir una variable con el mismo nombre tanto en el bucle for como fuera del bucle for es porque las variables en el alcance externo son válidas en el alcance interno. Lo que significa que habría dos variables 'i' dentro del ciclo for si se permitiera.
Ver: alcances de MSDN
Específicamente:
y
Y también: Declaraciones de variables locales (Sección 8.5.1 de la especificación C #)
Específicamente:
(El énfasis es mío).
Lo que significa que el alcance del
iinterior de su ciclo for es el ciclo for. Mientras que el alcance deliexterior de su ciclo for es el método principal completo más el ciclo for. Lo que significa que tendría dos ocurrenciasidentro del bucle que no es válido de acuerdo con lo anterior.La razón por la que no se le permite hacer
int A = i;es porqueint isolo tiene un alcance para su uso dentro delforciclo. Por lo tanto, ya no es accesible fuera delforbucle.Como puede ver, estos dos problemas son el resultado del alcance; El primer problema (
int i = 4;) daría como resultado dosivariables dentro delforalcance del bucle. Mientras queint 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 el
ialcance de todo el método y luego usarlo tanto en el método como en el ámbito del bucle for. Esto evitará romper cualquiera de las reglas.EDITAR :
Por supuesto, el compilador de C # podría modificarse para permitir que este código se compile de manera bastante válida. Después de todo esto es válido:
Pero, ¿sería realmente beneficioso para la legibilidad y facilidad de mantenimiento de su código poder escribir código como:
Piense en el potencial de errores aquí, ¿el último
iimprime 0 o 4? Ahora, este es un ejemplo muy pequeño, uno que es bastante fácil de seguir y rastrear, pero definitivamente es mucho menos fácil de mantener y leer que haber declarado el exterioricon 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 dentro del alcance desde donde se declaran hasta el final del bloque. Lo que haría que su código sea una construcción válida en C ++.
fuente
ivariable interna ; eso me parece más obvio.idefinición externa se moviera antes del ciclo for, laidefinición interna se marcaría como no válida.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 usar un nombre simple para referirse a dos entidades diferentes dentro de dos espacios de declaración de variables locales superpuestos diferentes. Entonces, no solo su ejemplo es ilegal, también es ilegal:
Porque ahora el nombre simple "x" se ha utilizado 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.
fuente
int y = this.x;this.xNo es un nombre simple .Hay una forma de declarar y usar
identro del método después del ciclo:Puede hacer esto en Java (podría originarse en C, no estoy seguro). Por supuesto, es un poco desordenado por el bien de un nombre de variable.
fuente
Si ha declarado
iantes de suforciclo, ¿cree que aún debería ser válido declararlo dentro del ciclo?No, porque entonces el alcance de los dos se superpondría.
En cuanto a no poder hacerlo
int A=i;, bueno, eso es simplemente porqueisolo existe en elforbucle, como debería ser.fuente
Además de la respuesta de J.Kommer (+1 por cierto). Hay esto en el estándar para el alcance NET:
Por lo tanto, el int i decalared dentro del encabezado del bucle for solo estará dentro del alcance durante el bloque del bucle for, PERO su vida útil dura hasta
Main()que se complete el código.fuente
La forma más fácil de pensar en esto es mover la declaración externa de I por encima del bucle. Debería ser obvio entonces.
Es el mismo alcance de cualquier manera, por lo tanto, no se puede hacer.
fuente
Además, las reglas de C # muchas veces no son necesarias en términos de programación estricta, pero están ahí para mantener su código limpio y legible.
por ejemplo, podrían haberlo hecho de modo que si lo define después del ciclo, entonces está bien, sin embargo, si alguien lee su código y omite la línea de definición, puede pensar que tiene que ver con la variable del ciclo.
fuente
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 for y el bloque exterior adjunto, de modo que el código dentro del bloque for 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 el interior como el exterior, una variable declarada en ambos lugares no se puede utilizar de forma inequívoca por su nombre.
Entonces, ¡o no lo ves, o eres C #!
fuente
Míralo de la misma manera que si pudieras declarar un
inten unusingbloque:Sin embargo, dado
intque no se implementaIDisposable, esto no se puede hacer. Sinintembargo, puede ayudar a alguien a visualizar cómo se coloca una variable en un ámbito privado.Otra forma sería decir:
Espero que esto ayude a visualizar lo que está sucediendo.
Realmente me gusta esta característica, ya que declarar
intdesde el interior delforbucle mantiene el código agradable y ajustado.fuente
usingestá bastante bien, aunque la semántica es bastante diferente (por lo que tal vez se rechazó). Tenga en cuenta queif (true)es redundante. Quítelo y tendrá un bloque de alcance.