Pourquoi C # autorise-t-il {} les blocs de code sans instruction précédente?

86

Pourquoi C # permet blocs de code sans une déclaration précédente (par exemple if, else, for, while)?

void Main()
{
    {   // any sense in this?
        Console.Write("foo");
    }
}
Seldon
la source
70
Y a-t-il une raison pour laquelle cela ne devrait pas ?
Jamiec
30
Mais comme le montrent les réponses, cela a plus de sens que simplement "ne fait pas mal, alors permettez-le". C'est un point de poser de telles questions.
Seldon
8
+1 question semble assez innocente, mais les réponses m'ont vraiment appris quelque chose de précieux
Nicolas78
7
@Akash: Sans demander pourquoi, nous ne nous améliorerons jamais.
richard
7
@Akash: Cela semble être une attitude élitiste audacieuse. Les gens ont toujours des questions, et s'il n'y a aucune raison de demander pourquoi, cela ne sert à rien d'avoir une SO. Ce site n'est pas tant pour permettre aux gens de résoudre nos problèmes immédiats (bien que cela se produise), mais pour fournir un référentiel de questions et réponses qui nous aideront tous à être de meilleurs programmeurs. SO est de demander POURQUOI! :-)
richard

Réponses:

90

Dans le contexte que vous donnez, il n'y a aucune signification. L'écriture d'une chaîne constante sur la console fonctionnera de la même manière partout dans le déroulement du programme. 1

Au lieu de cela, vous les utilisez généralement pour restreindre la portée de certaines variables locales. Ceci est développé ici et ici . Regardez la réponse de João Angelo et la réponse de Chris Wallis pour des exemples de brefs. Je pense que la même chose s'applique à certains autres langages avec une syntaxe de style C, non pas qu'ils seraient pertinents pour cette question.


1 À moins, bien sûr, vous décidez d'essayer d'être drôle et de créer votre propre Consoleclasse, avec une Write()méthode qui fait quelque chose de tout à fait inattendu.

BoltClock
la source
24
Re: autres langues: généralement, mais pas toujours. JavaScript est une exception notable; la déclaration d'une variable locale dans un bloc particulier ne porte pas la variable au bloc.
Eric Lippert
@EricLippert: En C #, la déclaration d'une variable dans un bloc entraîne-t-elle la portée de la variable du point de vue de l'exécution? D'après ce que je peux dire, les durées de vie des variables ne sont souvent pas limitées par des blocs de portée, un fait qui est observable dans les projets en langage mixte si la première chose à faire avec une variable dans une boucle est de la passer en outparamètre à une implémentation d'interface écrite dans un autre langage, et cette implémentation lit la variable avant de l'écrire.
supercat du
Et en C ++, à cause de RAII au lieu de GC, c'est beaucoup plus utile.
Deduplicator
En C ++, il agit un peu comme un bloc try / catch, donc les variables et les classes déclarées dans cette portée sortent de la pile lorsque vous quittez cette portée. Cela permet d'éviter les collisions de noms et de réduire l'empreinte mémoire de la fonction. Il supprime également ces variables de l'auto-complétion de l'éditeur de code. Souvent, je trouve les blocs try / catch plus utiles.
Kit 10
144

Le { ... }a au moins pour effet secondaire d'introduire une nouvelle portée pour les variables locales.

J'ai tendance à les utiliser dans des switchdéclarations pour fournir une portée différente pour chaque cas et me permettant ainsi de définir une variable locale avec le même nom à l'emplacement le plus proche possible de leur utilisation et pour indiquer également qu'elles ne sont valables qu'au niveau du cas.

João Angelo
la source
6
Cela vaut la peine de lire blogs.msdn.com/b/ericlippert/archive/2009/08/03/…
Dan Diplo
6
Si vous avez besoin de lunettes dans vos boîtiers, elles sont trop grandes! Méthode d'extraction.
Jay Bazuzi
20
@Jay Bazuzi, ce n'est pas parce que je veux avoir une variable locale avec le même nom dans plus d'un cas qu'elle doit être énorme. Vous sautez juste à d' énormes conclusions ... :)
João Angelo
Félicitations pour votre badge Great Answer! :)
BoltClock
1
@BoltClock, merci, j'ai juste besoin de plus de questions {}pour garder ces badges d'or à venir ... :)
João Angelo
56

Ce n'est pas tant une fonctionnalité de C # qu'un effet secondaire logique de nombreux langages de syntaxe C qui utilisent des accolades pour définir la portée .

Dans votre exemple, les accolades n'ont aucun effet, mais dans le code suivant, elles définissent la portée, et donc la visibilité, d'une variable:

Ceci est autorisé car i tombe hors de portée dans le premier bloc et est défini à nouveau dans le suivant:

{
    {
        int i = 0;
    }

    {
        int i = 0;
    }
}

Cela n'est pas autorisé car i est tombé hors de portée et n'est plus visible dans la portée externe:

{
    {
        int i = 0;
    }

    i = 1;
}

Ainsi de suite.

Chris Wallis
la source
1
J'ai lu des informations sur les disparités dans la nomenclature des parenthèses dans diverses saveurs de l'anglais, mais dans quelles saveurs sont {}appelées parenthèses?
BoltClock
Bonne question! J'imagine qu'un de mes mentors l'a planté dans mon cerveau il y a dix ans. Je devrais probablement les appeler «accolades» ou «accolades». Chacun à son propre ... fr.wikipedia.org/wiki/…
Chris Wallis
10
Dans mon vocabulaire '(' = parenthèse, '{' = accolade, '[' = crochets
pb.
Attendez, je les appellerais une parenthèse bouclée, et Wikipedia inclut cette dénomination. L'Oxford English Dictionary définit cette utilisation du crochet comme suit: One of two marks of the form [ ] or ( ), and in mathematical use also {}, used for enclosing a word or number of words, a portion of a mathematical formula, or the like, so as to separate it from the context; Dans tous les cas, ce ne sont pas des parenthèses, mais «crochet bouclé» semble correct.
dumbledad
IME, "accolades" et "crochets".
cp.engr
18

Je considère {}comme une déclaration pouvant contenir plusieurs déclarations.

Considérez une instruction if qui existe à partir d'une expression booléenne suivie d' une instruction. Cela fonctionnerait:

if (true) Console.Write("FooBar");

Cela fonctionnerait également:

if (true)
{
  Console.Write("Foo");
  Console.Write("Bar");
}

Si je ne me trompe pas, cela s'appelle une instruction de bloc.

Puisque {}peut contenir d'autres instructions, il peut également en contenir d'autres {}. La portée d'une variable est définie par son parent {}(instruction de bloc).

Le point que j'essaie de faire valoir est que ce {}n'est qu'une déclaration, donc cela ne nécessite pas de si ou quoi que ce soit ...

RBaarda
la source
+1 C'est exactement ce que sont les accolades dans les langages de style C - une soi-disant «instruction composée».
Michael Ekstrand
12

La règle générale dans les langages de syntaxe C est que "tout ce qui se trouve entre { }doit être traité comme une seule instruction, et il peut aller partout où une seule instruction le peut":

  • Après un if.
  • Après un for, whileou do.
  • N'importe où dans le code .

À toutes fins utiles, c'est comme la grammaire de la langue incluait ceci:

     <statement> :== <definition of valid statement> | "{" <statement-list> "}"
<statement-list> :== <statement> | <statement-list> <statement>

Autrement dit, "une instruction peut être composée de (diverses choses) ou d'une accolade ouvrante, suivie d'une liste d'instructions (qui peut inclure une ou plusieurs instructions), suivie d'une accolade fermée". IE "un { }bloc peut remplacer n'importe quelle instruction, n'importe où". Y compris au milieu du code.

Ne pas autoriser un { }bloc à un endroit où une seule instruction peut aller aurait en fait rendu la définition du langage plus complexe .

Massimo
la source
Quelqu'un vient d'augmenter cette réponse (après 9 ans), qui n'était pas en fait une réponse spécifique à cette question, mais bien plus une discussion générique. Elle a peut-être été remplacée par le langage et les bibliothèques .. Mais c'était quand même un plaisir, merci.
Massimo le
1

Parce que C ++ (et java) autorisait les blocs de code sans instruction précédente.

C ++ les a autorisés parce que C l'a fait.

On pourrait dire que tout se résume au fait que la conception du langage de programme américain (basé sur C) a gagné plutôt que la conception du langage de programme européen ( basé sur Modula-2 ).

(Les instructions de contrôle agissent sur une seule instruction, les instructions peuvent être des groupes pour créer de nouvelles instructions)

Ian Ringrose
la source
Voulez-vous dire Module2 ou Modula2?
Richard Ev
En effet, c'est la bonne réponse. De plus, je répondrais simplement "Parce que chaque langage informatique le fait."
Fattie le
1
// if (a == b)
// if (a != b)
{
    // do something
}
utilisateur202448
la source
0

1 Parce que ... il maintient la zone de portée de l'instruction .. ou de la fonction, ceci est vraiment utile pour gérer le gros code.

{
    {
        // Here this 'i' is we can use for this scope only and out side of this scope we can't get this 'i' variable.

        int i = 0;
    }

    {
        int i = 0;
    }
}

entrez la description de l'image ici

Raj
la source
0

Vous avez demandé "pourquoi" C # autorise les blocs de code sans instructions précédentes. La question "pourquoi" pourrait également être interprétée comme "quels seraient les avantages possibles de ce concept?"

Personnellement, j'utilise des blocs de code sans instruction en C # où la lisibilité est grandement améliorée pour les autres développeurs, tout en gardant à l'esprit que le bloc de code limite la portée des variables locales. Par exemple, considérez l'extrait de code suivant, qui est beaucoup plus facile à lire grâce aux blocs de code supplémentaires:

OrgUnit world = new OrgUnit() { Name = "World" };
{
    OrgUnit europe = new OrgUnit() { Name = "Europe" };
    world.SubUnits.Add(europe);
    {
        OrgUnit germany = new OrgUnit() { Name = "Germany" };
        europe.SubUnits.Add(germany);

        //...etc.
    }
}
//...commit structure to DB here

Je suis conscient que cela pourrait être résolu plus élégamment en utilisant des méthodes pour chaque niveau de structure. Mais là encore, gardez à l'esprit que des choses comme les semeurs d'échantillons de données doivent généralement être rapides.

Ainsi, même si le code ci-dessus est exécuté de manière linéaire, la structure du code représente la structure "du monde réel" des objets, facilitant ainsi la compréhension, la maintenance et l'extension des autres développeurs.

Marco
la source