2008-11-17 16 views
22

No se puede compilar el siguiente código indicando "Una variable local llamada 'st' no se puede declarar en este ámbito porque daría un significado diferente a 'st', que ya se usa en un ámbito 'secundario' para denotar algo más ":Child Scope & CS0136

 var l = new List<string>(); 
     l.Find(st => st.EndsWith("12")); 
     string st = "why this fails?"; 

entiendo por qué esto no funcionará:

 string preParent = ""; 
     { 
      string preParent = "Should fail cause we change the meaning"; 
     } 

Cuando hacemos lo que después de conseguir" CS0103: el nombre 'postParent' no existe en el actual contexto ":

 { 
      string postParent=string.Empty; 
     } 
     postParent = "Should this work?"; 

Lo que no entiendo es por qué el compilador es lo suficientemente inteligente para ver que postParent no está dentro del alcance, pero no me permite definir una nueva variable que tenga el mismo nombre que una variable utilizada en un ámbito hijo (que obviamente está fuera de alcance en este punto).

¿Es el compilador el ámbito de aplicación simple negándose a dejarme usar la variable? Si es así, esto tiene sentido.

===========

Editado:

Creo que lo que también me parece interesante es cómo se puede tener la misma variable dentro de los dos ámbitos secundarios en un único método, por lo esto es válido:

 { 
      string thisWorks= string.Empty; 
     } 
     { 
      string thisWorks= "Should this work?"; 
     } 

Sólo soy un poco curioso que se puede tener dos variables con el mismo nombre que siempre y cuando estén en el mismo nivel (si nos fijamos en alcance como un árbol). Esto tiene sentido porque puede tener variables locales en dos métodos de la misma clase con el mismo nombre.

Me sorprende que el compilador pueda diferenciar y permitir esto, mientras que no permitiría la variable postParent. ¿Y esto es una limitación técnica o fue esta una decisión de diseño? Eso es lo que realmente estoy tratando de conseguir ;-)

+2

¿Por qué un voto a favor después de 5 meses? – JoshBerke

Respuesta

12

Sí, el compilador está aplicando el alcance. Tenga en cuenta que el alcance de una variable es el bloque léxico del que forma parte, no solo desde el punto de declaración en adelante, sino desde el alcance completo.

El compilador se queja porque la asignación a postParent está fuera de su alcance (que son solo las llaves anidadas). Si intentó declarar una nueva variable en el punto donde está asignando actualmente a postParent, el problema sería con el bloque anidado, porque el alcance de postParent incluiría ese bloque anidado, incluso si era anterior a la declaración.

Los ámbitos se describen en la sección 3.7 de la especificación C# 3.0.

EDITAR: Para responder a la edición de su pregunta.

Es tan sólo dos reglas simples:

  • no se puede declarar una variable local cuando otra variable local con el mismo nombre está en el ámbito
  • el ámbito de una variable local es el bloque en el que la declaración ocurre

Estoy seguro de que el lenguaje podría haber sido diseñado de tal manera que el alcance solo comenzó en el momento de la declaración, pero creo que es más simple (en términos de complejidad del lenguaje) todas las variables locales declaradas en el mismo bloque tiene el mismo alcance, por ejemplo. Eso simplifica mucho la vida al considerar las variables capturadas, ya que lo que se captura depende del alcance, y los ámbitos anidados hacen la vida interesante ...

EDITAR: La especificación de idioma tiene esto que decir sobre el ejemplo de expresión lambda original - es la sección 7.14.1:

el opcional -función anónima firma de una función anónima define los nombres y, opcionalmente, los tipos de los parámetros formales para la función anónima. El alcance de los parámetros de la función anónima es anonymous-function-body. Junto con la lista de parámetros (si se proporciona), anonymous-method-body constituye un espacio de declaración . Por esta razón, es un error en tiempo de compilación para el nombre de un parámetro de la función anónima para que coincida con el nombre de un variable local, constante local o parámetro cuyo alcance incluye la -método de expresión anónima o lambda-expression.

¿Eso ayuda?

+0

Independientemente de si es por eso que aplica esa regla, todavía creo que esto es un defecto en el CLR. Los métodos anónimos definitivamente deberían desviar cualquier variable creada dentro de ellos de cualquier otra función, incluso si es tan simple como que CLR agregue un prefijo a cada variable en el método delegado. –

+2

El CLR no está involucrado en absoluto aquí. Es una decisión de lenguaje. Y estoy totalmente en desacuerdo. El punto es que las variables externas están disponibles para la función anónima, por lo que la función anónima no puede redefinirlas, exactamente de la misma manera que si la variable se redeclarase en un bloque "normal". –

+0

Tiene sentido ya que, suponiendo que la declaración sea parte del bloque de alcance total, no tendría forma de saber si la variable externa debería incluirse en la función anónima o no. Si se basa en el origen del alcance de la variable, puede permitirlo. – JoshBerke

-2

Está declarando una variable en un ámbito limitado e intentando usarla fuera de ese alcance. El compilador supone que no desea tener acceso a él, por lo que puede declarar una variable con el mismo nombre en otro lugar del archivo. Estás tratando de hacer el viejo truco C de suponer que la variable vivirá inmediatamente fuera del alcance. Por ejemplo, esto solía funcionar en versiones anteriores de C/C++ pero ya no funciona.

for (int i=0; i<10; i++) 
{ 
    cout <<”In the loop i is “<< i << endl; 
} 
cout << “outside of the loop i is “ << i << endl; //this only compiles with old C/C++ compilers. 
+2

Jared eso no es lo que estaba tratando de hacer ;-) C# no te permite declarar una variable con el mismo nombre si esa variable es declarado dentro del alcance de un niño. – JoshBerke