2010-03-22 18 views
56

Un problema si presentava su un altro forum e sapevo come risolverlo, ma rivelava una caratteristica del compilatore peculiare per me. La persona stava ricevendo l'errore "L'istruzione incorporata non può essere una dichiarazione o un'istruzione etichettata" perché avevano una dichiarazione di una variabile che segue un'istruzione if senza parentesi. Non era quello il loro intento, ma avevano commentato la riga di codice immediatamente successiva all'istruzione if, che rendeva la dichiarazione delle variabili la linea di codice de facto da eseguire. Ad ogni modo, quello è lo sfondo, che mi porta a questo.Dichiarazioni di variabili che seguono se dichiarazioni

Il seguente codice è illegale

if (true) 
    int i = 7; 

Tuttavia, se si avvolge che tra parentesi, è tutto legale.

if (true) 
{ 
    int i = 7; 
} 

Nessun pezzo di codice è utile. Eppure il secondo è OK. Qual è in particolare la spiegazione di questo comportamento?

risposta

76

Il C# language specification distingue tra tre tipi di dichiarazioni (vedi capitolo 8 per ulteriori dettagli). In generale, si può avere queste dichiarazioni:

  • etichettato-dichiarazione - la mia ipotesi che questo è per il vecchio stile goto dichiarazione
  • dichiarazione-dichiarazione - che sarebbe una dichiarazione di variabile
  • embedded-statement - che include praticamente tutte le restanti dichiarazioni

Negli if dichiarazione il corpo deve essere la dichiarazione incorporata, che spiega perché la prima versione del codice non funziona. Ecco la sintassi di if dalla specifica (sezione 8.7.1):

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

una dichiarazione di variabile è dichiarazione-dichiarazione, quindi non può apparire nel corpo. Se si racchiude la dichiarazione tra parentesi, si otterrà un blocco di istruzioni, che è una istruzione incorporata (e quindi può apparire in quella posizione).

27

Quando non si includono le parentesi, si esegue la riga successiva come se fosse circondata da parentesi. Dal momento che non ha molto senso dichiarare una variabile in quella linea (non saresti in grado di usarla mai), il compilatore C# non permetterà che questo ti impedisca di farlo accidentalmente senza sapere (che potrebbe introdurre bug sottili).

Ecco parte di Eric Lippert ha da dire circa il compilatore C# su this SO answer sulla risoluzione dei nomi:

...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

Sono d'accordo, non ha senso a tutti di dichiarare una variabile in questo modo. Tuttavia la dichiarazione di variabile completamente inutile nel secondo esempio va bene. Né è di valore. È semplicemente una questione di parentesi, nient'altro? (A proposito, posso conviverci.) –

+3

Sì. Le tue intenzioni sono assolutamente chiare al compilatore quando includi le parentesi, quindi lo permetterà. Il compilatore C# non lo consentirà senza parentesi, poiché non è chiaro che la tua intenzione effettiva sia dichiarare una variabile inutile. –

+0

Ma il secondo potrebbe benissimo essere di valore - se, ad esempio, il valore viene recuperato da un metodo che ha effetti collaterali. –

9

tutti i compilatori vi permetterà di compilare il codice che è inutile o di utilizzo estremamente basso. Ci sono semplicemente troppi modi in cui uno sviluppatore può usare il linguaggio per creare costrutti senza alcuno scopo. Avere il compilatore catturato tutti loro è semplicemente uno sforzo eccessivo e in genere non ne vale la pena.

Il secondo caso è chiamata direttamente nella specifica linguaggio C# all'inizio della sezione di 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.

Esempio di codice

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

Grazie per l'input, molto utile. –

0

Aggiungendo le parentesi graffe di apertura e di chiusura sulla parte opposta del if se mi ha aiutato come ho fatto di seguito rispetto a quello che stavo facendo prima di aggiungerli;

Prima: questo ha causato l'errore:

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); 
    } 

Dopo: parentesi aggiunti nel ramo altro

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); 
    } 
Problemi correlati