web-dev-qa-db-fra.com

Déclarations de variables après les 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 était particulière. La personne obtenait l'erreur "L'instruction incorporée ne peut pas être une déclaration ou une instruction étiquetée" car elle avait une déclaration d'une variable suivant 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. Quoi qu'il en soit, c'est le contexte 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?

59
Anthony Pegram

Le 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:

  • instruction-étiquetée - je suppose que c'est pour l'ancienne instruction goto
  • déclaration-déclaration - qui serait une déclaration de variable
  • instruction intégrée - qui comprend à peu près toutes les instructions restantes

Dans l'instruction if, le corps doit être instruction-intégré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 ) instruction-intégrée
if ( expression-booléenne ) instruction-intégrée else instruction intégrée

Une déclaration de variable est déclaration-déclaration , elle ne peut donc pas apparaître dans le corps. Si vous placez la déclaration entre crochets, vous obtiendrez un bloc d'instruction, qui est une instruction-intégrée (et donc elle peut apparaître dans cette position) .

80
Tomas Petricek

Lorsque vous n'incluez pas les crochets, il exécute la ligne suivante comme si elle était entourée de crochets. Comme cela n'a pas beaucoup de sens de déclarer une variable dans cette ligne (vous ne pourrez jamais l'utiliser), le compilateur C # ne permettra pas que cela vous empêche de le faire accidentellement sans le savoir (ce qui pourrait introduire des bogues subtils ).

Voici une partie d'Eric Lippert a à dire sur le compilateur C # sur this SO answer about resolution name:

... C # n'est pas un langage "devinez ce que l'utilisateur voulait dire" ... le compilateur par conception se plaint fortement si la meilleure correspondance est quelque chose qui ne fonctionne pas

27
Zach Johnson

Tous les compilateurs vous permettront de compiler du code inutile ou d'une utilisation extrêmement faible. Il existe tout simplement trop de façons dont un développeur peut utiliser le langage pour créer des constructions sans aucune utilité. Le fait que le compilateur les capture tous représente tout simplement trop d'efforts et n'en vaut généralement pas la peine.

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

L'exemple entraîne une erreur au moment de la compilation car une instruction if nécessite une instruction embedded plutôt qu'une instruction pour sa branche if. Si ce code était autorisé, 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;
}
10
JaredPar

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

Avant: cela a provoqué 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 crochets dans la branche 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);
    }
0
Kristin Kabajwisa