Déclarations de variables suivant des instructions if

Un problème est apparu sur un autre forum et je savais comment le résoudre, mais il a révélé une fonctionnalité du compilateur qui me semblait particulière. La personne recevait l’erreur “L’instruction incorporée ne peut pas être une déclaration ou une instruction étiquetée”, car elle avait une déclaration de variable à la suite d’une instruction if sans crochets. Ce n’était pas leur intention, mais ils avaient commenté la ligne de code immédiatement après l’instruction if, ce qui faisait de la déclaration de variable la ligne de code de facto à exécuter. En tout cas, c’est le contexte, ce qui m’amène à cela.

Le code suivant est illégal

if (true) int i = 7; 

Cependant, si vous mettez cela entre parenthèses, tout est légal.

 if (true) { int i = 7; } 

Aucun morceau de code n’est utile. Pourtant, le second est OK. Quelle est précisément l’explication de ce comportement?

La spécification du langage C # distingue trois types d’instructions (voir le chapitre 8 pour plus de détails). En général, vous pouvez avoir ces déclarations:

  • label-statement – je suppose que c’est pour la déclaration goto démodée
  • déclaration-déclaration – qui serait une déclaration de variable
  • déclaration incorporée – qui inclut à peu près toutes les déclarations restantes

Dans l’instruction if , le corps doit être une déclaration incorporée , ce qui explique pourquoi la première version du code ne fonctionne pas. Voici la syntaxe de if de la spécification (section 8.7.1):

if ( expression booléenne ) déclaration incorporée
if ( expression-booléenne ) déclaration -incorporée autre déclaration-incorporée

Une déclaration de variable est une déclaration , elle ne peut donc pas apparaître dans le corps. Si vous placez la déclaration entre parenthèses, vous obtenez un bloc d’instructions, qui est une instruction incorporée (et peut donc apparaître dans cette position).

Lorsque vous n’incluez pas les crochets, il exécute la ligne suivante comme s’il était entouré de crochets. Comme il n’est pas très logique de déclarer une variable dans cette ligne (vous ne pourriez jamais l’utiliser), le compilateur C # ne vous permettra pas de le faire sans vous en rendre compte (ce qui pourrait introduire des bogues subtils). ).

Voici une partie d’Eric Lippert à propos du compilateur C # sur cette réponse SO à propos de la résolution de noms:

… C # n’est pas un “devine ce que veut dire l’utilisateur” le langage … le compilateur par conception se plaint bruyamment si le meilleur match est quelque chose qui ne fonctionne pas

Tous les compilateurs vous permettront de comstackr du code inutile ou d’une utilisation extrêmement faible. Il y a tout simplement trop de façons qu’un développeur peut utiliser le langage pour créer des constructions sans utilisation. Avoir le compilateur tous attrape tout simplement trop d’effort et ne vaut généralement pas la peine.

Le second cas est appelé directement dans la spécification du langage C # au début de la section 8.0.

L’exemple donne lieu à une erreur de compilation car une instruction if nécessite une instruction incorporée plutôt qu’une instruction pour sa twig if. Si ce code était autorisé, alors la variable i serait déclarée, mais elle ne pourrait jamais être utilisée. Notez cependant qu’en plaçant la déclaration de i dans un bloc, l’exemple est valide.

Exemple de code

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

L’ajout des accolades de fermeture et d’ouverture sur la partie restante de l’if m’a aidé comme je l’ai fait ci-dessous par opposition à ce que je faisais avant de les append;

Avant: cela provoquait l’erreur:

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

Après: Ajout de parenthèses dans la twig 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); }