2010-03-22 40 views
56

Se produjo un problema en otro foro y supe cómo solucionarlo, pero reveló una característica del compilador peculiar para mí. La persona obtenía el error "La declaración incrustada no puede ser una declaración o una declaración etiquetada" porque tenían una declaración de una variable que seguía una instrucción if sin corchetes. Esa no era su intención, pero habían comentado la línea de código que sigue inmediatamente a la declaración if, que hacía que la declaración de la variable fuera la línea de código de facto que debía ejecutarse. De todos modos, ese es el fondo, lo que me lleva a esto.Declaraciones de variables después de sentencias if

El siguiente código es ilegal

if (true) 
    int i = 7; 

Sin embargo, si envuelves que entre paréntesis, es todo legal.

if (true) 
{ 
    int i = 7; 
} 

Ninguna parte del código es útil. Sin embargo, el segundo está bien. ¿Cuál es específicamente la explicación de este comportamiento?

Respuesta

76

El C# language specification distingue entre tres tipos de declaraciones (véase el capítulo 8 para más detalles). En general se puede tener estas declaraciones:

  • marcado con declaración - yo creo que esto es para el anticuado goto comunicado
  • declaración-declaración - lo que sería una declaración de variables
  • incrustado-declaración - que incluye prácticamente todos los estados restantes

de estado if instrucción el cuerpo tiene que ser incrustado-instrucción, lo que explica por qué la primera versión del código no funciona. Aquí está la sintaxis de if de la especificación (sección 8.7.1):

if (boolean-expression) embedded-statement
if (boolean-expression) embedded-statement else embedded-statement

Una declaración de variables es declaración-declaración, por lo que no puede aparecer en el cuerpo. Si encierra la declaración entre paréntesis, obtendrá un bloque de instrucciones, que es incrustado (y por lo tanto puede aparecer en esa posición).

27

Cuando no incluye los corchetes, ejecuta la siguiente línea como si estuviera rodeada por corchetes. Dado que no tiene mucho sentido declarar una variable en esa línea (no podrá usarla nunca), el compilador de C# no permitirá que esto evite que lo haga accidentalmente sin saberlo (lo que podría introducir errores sutiles).)

Aquí es parte de Eric Lippert tiene que decir sobre el compilador de C# en this SO answer acerca de la resolución de nombres:

...C# is not a "guess what the user meant" language...the compiler by design complains loudly if the best match is something that doesn't work

+1

Estoy de acuerdo, no tiene sentido en absoluto para declarar una variable de tal manera. Sin embargo, la declaración variable completamente inútil en el segundo ejemplo está bien. Ninguno de los dos tiene valor. ¿Es simplemente una cuestión de poner entre paréntesis, nada más? (Por cierto, puedo vivir con eso) –

+3

Sí. Sus intenciones son absolutamente claras para el compilador cuando incluye los corchetes, por lo que lo permitirá. El compilador de C# no lo permitirá sin corchetes, ya que no está claro que su intención real sea declarar una variable inútil. –

+0

Pero el segundo bien podría ser de valor, si, por ejemplo, el valor se recupera de un método que tiene efectos secundarios. –

9

Todos los compiladores permitirá compilar código que es inútil o de uso excesivamente bajo. Simplemente hay demasiadas formas en que un desarrollador puede usar el lenguaje para crear constructos sin uso. Hacer que el compilador los atrape a todos es simplemente demasiado esfuerzo y, por lo general, no vale la pena.

El segundo caso se llama a cabo directamente en la especificación del lenguaje C# al inicio de la sección 8,0

The example results in a compile-time error because an if statement requires an embedded-statement rather than a statement for its if branch. If this code were permitted, then the variable i would be declared, but it could never be used. Note, however, that by placing i’s declaration in a block, the example is valid.

Ejemplo Código

void F(bool b) { 
    if (b) 
     int i = 44; 
} 
+0

Gracias por la entrada, muy beneficioso. –

0

Añadiendo las llaves de cierre y apertura en la parte else del si me ayudó como he hecho a continuación en comparación con lo que estaba haciendo antes de agregarlos;

Antes: esto causó el error:

protected void btnAdd_Click(object sender, EventArgs e) 
    { 
     if (btnAdd.Text == "ADD") 
     { 

      CATEGORY cat = new CATEGORY 
      { 

       NAME = tbxCategory.Text.Trim(), 
       TOTALSALEVALUE = tbxSaleValue.Text.Trim(), 
       PROFIT = tbxProfit.Text.Trim() 

      }; 
      dm.AddCategory(cat, tbxCategory.Text.Trim()); 
     } 
     else 
     // missing brackets - this was causing the error 
      var c = getCategory(); 
      c.NAME = tbxCategory.Text.Trim(); 
      c.TOTALSALEVALUE = tbxSaleValue.Text.Trim(); 
      c.PROFIT = tbxProfit.Text.Trim(); 
      dm.UpdateCategory(c); 

     btnSearchCat_Click(btnSearchCat, e); 
    } 

Después de: soportes añadido en la rama else

protected void btnAdd_Click(object sender, EventArgs e) 
    { 
     if (btnAdd.Text == "ADD") 
     { 

      CATEGORY cat = new CATEGORY 
      { 

       NAME = tbxCategory.Text.Trim(), 
       TOTALSALEVALUE = tbxSaleValue.Text.Trim(), 
       PROFIT = tbxProfit.Text.Trim() 

      }; 
      dm.AddCategory(cat, tbxCategory.Text.Trim()); 
     } 
     else 
     { 
      var c = getCategory(); 
      c.NAME = tbxCategory.Text.Trim(); 
      c.TOTALSALEVALUE = tbxSaleValue.Text.Trim(); 
      c.PROFIT = tbxProfit.Text.Trim(); 
      dm.UpdateCategory(c); 
     } 
     btnSearchCat_Click(btnSearchCat, e); 
    } 
Cuestiones relacionadas