2011-01-10 15 views
11

Como por ejemplo:¿Por qué C# no me permite usar el mismo nombre de variable en diferentes ámbitos?

if (this.IsValid) 
{ 
    Matrix matrix = new Matrix(); 
} 

Matrix matrix = new Matrix(); 

El compilador advierte mí diciendo:

"Una variable local llamada 'matrix' no puede ser declarado en este ámbito, ya que daría un significado diferente a 'matrix', que ya se utiliza en un ámbito de 'niño' para denotar algo más.

¿no son estas variables en diferentes ámbitos, por lo que no sería capaz de acceder a la primera matrix desde fuera si la declaración de todos modos?

+0

Incluso si la pregunta es elegible, esto evita que cometa errores por descuido. –

+0

aquí [http://bytes.com/topic/c-sharp/answers/659303-already-used-child-scope-denote-something-else] puede encontrar una explicación de Jon Skeet. Y aquí http://stackoverflow.com/questions/296755/child-scope-cs0136 también por Jon Skeet. –

+0

@Tim: Sí, pero uno necesita hacer nuevos nombres de variables innecesarios, cada vez, se debe usar algo similar, solo para satisfacer al compilador. IMO si el código es claro, esto no causaría ningún problema. Puedo ver lo que significaba cada matriz sin hacer: matrixTemporary, matrixReal, etc. –

Respuesta

15

Las respuestas dadas hasta ahora son muy confusas. El análisis correcto del problema comienza por leyendo el mensaje de error. El mensaje de error que le está diciendo lo que es realmente malo:

"Una variable local llamada 'matriz' no se pueden declarar en este ámbito, ya que daría un significado diferente a 'matriz', que ya se utiliza en un ' alcance 'niño para denotar algo más.

leído que cuidadosamente.Le está diciendo con precisión qué regla de C# se está violando, es decir, , que no tiene permiso para usar el mismo nombre para referirse a dos cosas diferentes en el mismo ámbito. (En realidad, el mensaje de error es un poco incorrecto; debe decir "espacio de declaración de variable local" donde dice "alcance", pero es bastante prolijo).

Esta regla está documentada en la especificación C# 4.0, sección 7.6. 2.1: Nombres simples, significado invariable en bloques.

(se también ilegal tener dos variables locales del mismo nombre en la superposición de espacios de declaración. El compilador puede informando que el error así, sino que informa del error más general en este caso.)

¿No son estas variables en diferentes ámbitos, por lo que no podría acceder a la primera matriz desde fuera de la instrucción if de todos modos?

Sí. Esa declaración es verdadero pero irrelevante. El error aquí es que el mismo nombre simple se ha usado para referirse a dos cosas diferentes en el mismo espacio de declaración de variable local.

Considere este escenario:

class C 
{ 
    int x; 
    void M() 
    { 
     x = 10; // means "this.x" 
     for(whatever) 
     { 
      int x = whatever; 
     } 
    } 
} 

mismo trato. El error aquí es que el nombre simple "x" se usó en el espacio de declaración externo para referirse a this.x, y se usó en el espacio de declaración interno para significar "variable local". Usando el mismo nombre simple para referirse a dos cosas diferentes en el mismo espacio de declaración - recuerde, el espacio interno de declaración es parte del exterior - es ambos confundiendo y peligroso, y por lo tanto es ilegal.

Es confuso por razones obvias; uno tiene una expectativa razonable de que un nombre signifique lo mismo en todas partes a lo largo del espacio de declaración en el que se usa por primera vez. Es peligroso porque los pequeños cambios de código son propensos a cambiar el significado:

class C 
{ 
    int x; 
    void M() 
    { 
     int x; 
     x = 10; // no longer means "this.x" 
     for(whatever) 
     { 
      x = whatever; 
     } 
    } 
} 

Si los espacios de declaración en el que los nombres simples se utilizaron por primera vez se no se solapan entonces es legal para los nombres simples para referirse a diferentes cosas:

class C 
{ 
    int x; 
    void M() 
    { 
     { 
      x = 10; // means "this.x" 
     } 
     for(whatever) 
     { 
      int x = whatever; // Legal; now the 
     } 
    } 
} 

Para obtener más información, y una divertida historia acerca de los alimentos fritos, ver

http://blogs.msdn.com/b/ericlippert/archive/tags/simple+names/

+0

@Eric: gracias Eric. No entiendo cómo en su último ejemplo, second int x es válido. ¿Es porque encapsuló x = 10 con {} s? –

+1

@Joan: Correcto. Con x = 10 en un bloque propio, ahora el espacio de declaración de variable local que lo incluye no * se superpone * con el otro espacio de declaración de variable local que contiene el otro uso de x. –

+0

@Eric: Gracias Eric. Lo entiendo ahora. He visto algunos idiomas cuando estaba escrito como en tu primer ejemplo, el segundo x ocultaba el primero, ¿entonces crees que es un mal diseño? Por último, dijo en su comentario "... que encierra que no se superpone ...", ¿conoce un lugar que pueda aprender sobre el concepto de superposición en C#? No lo escuché antes. –

7

Creo que esto se hace para evitar errores oscuros o códigos que son difíciles de leer.

Utilizando el mismo nombre de variable entre un ámbito de método y de un ámbito secundario puede conducir a código que es muy difícil de leer, ya que el tipo de variable y, lo peor, es decir, puede cambiar y la única pista para el lector ser tipo declaración palabra clave antes de la variable.

Sin embargo, también puedo decirte que la IL generada por los métodos del compilador C# pegará todas las declaraciones de variables en la parte superior, por lo que tal vez este controlador de decisión simplifique el árbol de análisis variable para el compilador.

De hecho, usted puede encontrar esto en MSDN:

El alcance de nombre es la región de texto del programa dentro del cual es posible hacer referencia a la entidad declarado por el nombre sin calificación del nombre. Los ámbitos se pueden anidar , y un alcance interno puede redeclarar el significado de un nombre de un ámbito exterior. (Esto no, sin embargo, eliminar la restricción impuesta por Section 3.3 que dentro de un bloque anidado no es posible declarar una variable local con el mismo nombre como una variable local en un bloque de envolvente.) La se dice que el nombre del alcance externo está oculto en la región del texto del programa cubierto por el alcance interno, y el acceso al nombre externo solo es posible por calificando el nombre.

Énfasis añadido.

Y, a partir de la Sección 3.3:

Cada bloque o cambiar de bloque crea un espacio de declaración diferente para variables y constantes locales. Los nombres son introducidos en este espacio de declaración a través de declaraciones de variables locales y declaraciones de constantes locales.Si un bloque es el cuerpo de un constructor de instancias , método, o el operador declaración, o una escapada o un conjunto de acceso de una declaración indexador, los parámetros declarados en dicha declaración son miembros de declaración de variables locales del bloque espacio. El espacio de declaración de variable local de un bloque incluye cualquier bloque anidado. Por lo tanto, dentro de un bloque anidado no es posible declarar una variable local con el mismo nombre que una variable local en un bloque envolvente.

Énfasis añadido.

Por lo tanto, la cosa es que, si bien los alcances son diferentes, el espacio de las variables es el mismo.

2

Imagina a un ser humano tratando de leer este código.

Desde el punto de vista de otro desarrollador que intenta leer su código, ¿puede ver lo confuso que sería tener dos variables diferentes con el mismo nombre? Incluso si representan lo mismo, es demasiado difícil lidiar con dos cosas con el mismo nombre.

+0

No creo que sea confuso, porque muestra claramente que la matriz en el interior el if está destinado a ser temporal, por lo que podría crearse para hacer un determinado cálculo, etc. –

5

Siempre se puede hacer esto ...

void YourMethod() 
{ 
    if (this.IsValid) 
    {  
     Matrix matrix = new Matrix(); 
    } 

    { 
     Matrix matrix = new Matrix(); 
    } 
} 

... Cada conjunto de llaves {} que permite anidar otro nivel de alcance. El problema que está teniendo es el hecho de que los ámbitos anidados incluyen el alcance de sus padres. Si declara un alcance siblng, podrá reutilizar variables dentro del mismo padre. Pero, como otros han señalado, esto puede volverse confuso más adelante.

+0

Gracias pero no puedo. La segunda matriz y las instrucciones que la siguen deben ejecutarse siempre (ya sea esto.Es o no válido) –

+1

Para el usuario que baja. ¿Por qué está mal? Puede intentarlo. Descubrirás que eres el que está equivocado. El segundo conjunto de llaves declara un alcance secundario que siempre se ejecuta. No es uno o el otro. –

+0

@Joan, ejecutará ambos. –

1
Matrix matrix = new Matrix(); 

if (this.IsValid) 
{ 
    Matrix matrix = new Matrix(); 
} 

imaginarlo vez escrito el estilo, que es un poco más evidente me ocurre por qué esto no está permitido ya que la segunda instancia, obviamente, debe ser considerado como un choque. No poder acceder a las variables externas dentro de los ámbitos secundarios sería malo.

De MSDN "A:. Este es el comportamiento correcto, y se cubre en la sección 3.7 de la especificación de lenguaje Dice:“El alcance de una variable local declarada en una declaración-variable-local (8.5.1) es el bloque en el que se produce la declaración "." ... "Este comportamiento tiene la intención de hacer menos probable la reutilización incorrecta de nombres de variables (como cortar y pegar)." (http://blogs.msdn.com/b/csharpfaq/archive/2004/05/18/why-can-ti-use-the-same-variable-as-an-inner-loop-does.aspx)

+0

Eso parece más IMO contraintuitivo, pero incluso en ese caso, esperaría que el compilador ocultara la variable de ámbito externo y creara una nueva. Pero en mi ejemplo, uno pensaría que la primera matriz ya está en otro ámbito, por lo que no podría afectar a la segunda variable de matriz, como que su accesibilidad no va más allá de la instrucción if en la que está contenida. –

Cuestiones relacionadas