web-dev-qa-db-fra.com

Pourquoi ne pouvons-nous pas définir une variable à l'intérieur d'une instruction if?

Peut-être que cette question a déjà reçu une réponse, mais le mot if se produit si souvent qu'il est difficile de le trouver.

L'exemple n'a pas de sens (l'expression est toujours vraie), mais il illustre ma question.

Pourquoi ce code est-il valide:

StringBuilder sb;
if ((sb = new StringBuilder("test")) != null) {
    Console.WriteLine(sb);
}

Mais ce code n'est pas:

if ((StringBuilder sb = new StringBuilder("test")) != null) {
    Console.WriteLine(sb);
}

J'ai trouvé une question similaire concernant une instruction while. La réponse acceptée ici dit que dans une instruction while, cela signifierait que la variable serait définie dans chaque boucle. Mais pour mon exemple de déclaration if, ce n'est pas le cas.

Alors, quelle est la raison pour laquelle nous ne sommes pas autorisés à faire cela?

44
comecme

En effet, la section 8.5.1 de la spécification du langage C #. États:

De plus, un initialiseur de variable dans une déclaration de variable locale correspond exactement à une instruction d'affectation qui est insérée immédiatement après la déclaration.

Cela signifie essentiellement que, lorsque vous effectuez:

StringBuilder sb = new StringBuilder("test")

En fait, vous faites exactement la même chose que:

StringBuilder sb; sb = new StringBuilder("test")

En tant que tel, il n'y a plus de valeur de retour pour votre chèque par rapport à != null, car l'affectation n'est pas une expression unique, mais plutôt une instruction, qui est un local-variable-declarator composé d'un identifiant suivi d'une expression.

La spécification du langage donne cet exemple, déclarant que ceci:

void F() {
   int x = 1, y, z = x * 2;
}

Est exactement équivalent à:

void F() {
   int x; x = 1;
   int y;
   int z; z = x * 2;
}
37
Reed Copsey

Essayez Correspondance des motifs de C # 7 .

En utilisant votre exemple:

if (new StringBuilder("test") is var sb && sb != null) {
    Console.WriteLine(sb);
}
19
Jecoms

Cela a à voir avec la différence entre une déclaration et une expression. Une expression a une valeur, contrairement à une instruction.

À l'aide de vos exemples, notez ces classifications:

StringBuilder sb; // statement

sb = new StringBuilder("test") // expression

StringBuilder sb = new StringBuilder("test"); // statement

Notez que seule la partie médiane est une expression.

Nous passons maintenant à votre déclaration conditionnelle. La syntaxe d'utilisation de l'opérateur différent de est

expression != expression

Donc, des deux côtés de la != vous avez besoin de quelque chose qui a réellement une valeur (cela a du sens). Ergo, vous ne pouvez pas avoir de déclarations de chaque côté de l'opérateur. C'est pourquoi une version de votre code fonctionne, tandis que l'autre ne fonctionne pas.

9

Au lieu de:

if ((StringBuilder sb = new StringBuilder("test")) != null) {
    Console.WriteLine(sb);
}

On pourrait également écrire:

for (StringBuilder sb = new StringBuilder("test"); sb != null; sb = null) {
    Console.WriteLine(sb);
}

Cette boucle for s'exécutera une fois si votre variable n'est pas nulle. À la fin de la boucle, votre variable temporaire est définie sur null. La condition de boucle est ensuite évaluée à false et l'instruction suivante continue après l'exécution de l'accolade fermante. Exactement comme votre instruction if initialement prévue.

3
user809316