Confusión de scope variable en C #

Tengo dos muestras de código. El primero no comstack, pero el segundo sí.

Código de muestra 1 (no comstack)

public void MyMethod(){ int i=10; for(int x=10; x<10; x++) { int i=10; // Point1: compiler reports error var objX = new MyOtherClass(); } var objX = new OtherClassOfMine(); // Point2: compiler reports error } 

Entiendo por qué el comstackdor informa un error en Point1 . Pero no entiendo por qué informa un error en Point2 . Y si dice que es debido a la organización dentro de MSIL, ¿por qué comstack el segundo ejemplo de código?

Ejemplo de código 2 (comstack)

 public void MyMethod(){ for(int x=10; x<10; x++) { int i=10; var objX = new MyOtherClass(); } for(int x=10; x<10; x++) { int i=10; var objX = new MyOtherClass(); } } 

Si se aplican las reglas simples de scope variable en la Muestra de código 2, ¿por qué esas mismas reglas no se aplican a la Muestra de código 1?

Aquí hay dos reglas relevantes.

La primera regla relevante es:

Es un error que un espacio de statement de variable local y un espacio de statement de variable local nested contengan elementos con el mismo nombre.

(Y otra respuesta en esta página llama a otra ubicación en la especificación donde llamamos esto de nuevo).

Eso solo es suficiente para que esto sea ilegal, pero de hecho una segunda regla lo hace ilegal.

La segunda regla relevante en C # es:

Para cada aparición de un identificador dado como un nombre simple en una expresión o declarador, dentro del espacio de statement de variable local, encerrando inmediatamente el bloque o el bloque de conmutación de esa ocurrencia, cada otra aparición del mismo identificador como un nombre simple en una expresión o declarador dentro del bloque que lo rodea inmediatamente o bloque de interruptores debe referirse a la misma entidad. Esta regla garantiza que el significado de un nombre sea siempre el mismo dentro de un bloque, bloque de conmutación, instrucción for-, foreach- o using, o función anónima.

También necesita saber que un bucle for es tratado como si hubiera “llaves invisibles” alrededor de todo.

Ahora que lo sabemos, anotemos su código:

 public void MyMethod() { // 1 int i=10; // i1 { // 2 -- invisible brace for(int x=10; x<10; x++) // x2 { // 3 int i=10; // i3 var objX = new MyOtherClass(); // objX3 } // 3 } // 2 var objX = new OtherClasOfMine(); // objX1 } // 1 

Tienes tres "nombres simples", i, x y objX. Tiene cinco variables, que he etiquetado como i1, x2, i3, objX3 y objX1.

El bloque más externo que contiene usos de i y objX es el bloque 1. Por lo tanto, dentro del bloque 1, i y objX siempre deben referirse a la misma cosa. Pero ellos no. A veces me refiero a i1 y a veces se refiere a i3. Lo mismo con objX.

x, sin embargo, solo significa x2 en cada bloque.

Además, ambas variables "i" están en el mismo espacio de statement de variable local, ya que ambas son variables "objX".

Por lo tanto, este progtwig es un error de varias maneras.

En tu segundo progtwig:

 public void MyMethod() { // 1 { // 2 -- invisible for(int x=10; x<10; x++) // x2 { // 3 int i=10; // i3 var objX = new MyOtherClass(); // objX3 } //3 } // 2 { // 4 -- invisible for(int x=10; x<10; x++) // x4 { // 5 int i=10; // i5 var objX = new MyOtherClass(); // objX5 } //5 } // 4 } // 1 

Ahora tiene tres nombres simples nuevamente y seis variables.

Los bloques más externos que primero contienen un uso de nombre simple x son los bloques 2 y 4. A lo largo del bloque 2, x se refiere a x2. En todo el bloque 4, x se refiere a x4. Por lo tanto, esto es legal. Lo mismo con i y objX: se usan en los bloques 3 y 5 y significan cosas diferentes en cada uno. Pero en ninguna parte se usa el mismo nombre simple para referirse a dos cosas diferentes en el mismo bloque.

Ahora, puede observar que considerando todo el bloque 1 , x se usa para referirse tanto a x2 como a x4. Pero no se menciona a x que está dentro del bloque 1 pero NO también dentro de otro bloque. Por lo tanto, no contamos el uso inconsistente en el bloque 1 como relevante.

Además, ninguno de los espacios de statement se superpone de manera ilegal.

Por lo tanto, esto es legal.

De la especificación del lenguaje C # …

El scope de una variable local declarada en una statement de variable local es el bloque en el que se produce la statement. 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 scope de una variable local, es un error en tiempo de comstackción declarar otra variable local o constante con el mismo nombre.

En el ejemplo de código 1, tanto i como objX se declaran en el scope de la función, por lo que ninguna otra variable en ningún bloque dentro de esa función puede compartir un nombre con ellos. En el ejemplo de código 2, ambos objX se declaran dentro de los bucles for, lo que significa que no infringen la regla de no redeclar variables locales en ámbitos internos de otra statement.

Puede usar el mismo nombre de variable en ámbitos no superpuestos. Sin embargo, si un scope se superpone con otro, no puede tener la misma variable declarada en ambos. El motivo es evitar que accidentalmente utilice un nombre de variable ya utilizado en un ámbito interno, como lo hizo con i en el primer ejemplo. En realidad no es para evitar el error objX ya que, ciertamente, no sería muy confuso, pero el error es una consecuencia de cómo se aplica la regla. El comstackdor considera que objX tiene procedencia en todo el ámbito en el que se declara antes y después de su statement, no solo después.

En el segundo ejemplo, los dos lazos for tienen ámbitos independientes que no se superponen, por lo que puede reutilizar i y objX en el segundo ciclo. También es la razón por la que puedes reutilizar x como contador de bucle. Obviamente, sería una tonta restricción si tuviera que inventar diferentes nombres para cada uno for(i=1;i<10;++i) ciclos for(i=1;i<10;++i) en una función.

En una nota personal, encuentro que este error es molesto y prefiero la forma C / C ++ de permitirle hacer lo que quiera, la maldita condenación.

no debería obtener un error de comstackción con la segunda muestra. Intente cambiar el nombre de las variables a diferentes letras / nombres y recompile de nuevo, ya que puede haber otro problema con el código que probablemente haya omitido un corchete y haya cambiado el rango de scope de las variables.