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=i
Respuestas:
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
i
interior de su ciclo for es el ciclo for. Mientras que el alcance deli
exterior de su ciclo for es el método principal completo más el ciclo for. Lo que significa que tendría dos ocurrenciasi
dentro 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 i
solo tiene un alcance para su uso dentro delfor
ciclo. Por lo tanto, ya no es accesible fuera delfor
bucle.Como puede ver, estos dos problemas son el resultado del alcance; El primer problema (
int i = 4;
) daría como resultado dosi
variables dentro delfor
alcance 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
i
alcance 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
i
imprime 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 exteriori
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 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
i
variable interna ; eso me parece más obvio.i
definición externa se moviera antes del ciclo for, lai
definició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.x
No es un nombre simple .Hay una forma de declarar y usar
i
dentro 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
i
antes de sufor
ciclo, ¿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 porquei
solo existe en elfor
bucle, 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
int
en unusing
bloque:Sin embargo, dado
int
que no se implementaIDisposable
, esto no se puede hacer. Sinint
embargo, 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
int
desde el interior delfor
bucle mantiene el código agradable y ajustado.fuente
using
está 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.