Warum erlaubt C # {} Codeblöcke ohne vorhergehende Anweisung?

86

Warum C # ermöglicht Codeblöcke ohne vorherige Anweisung (zB if, else, for, while)?

void Main()
{
    {   // any sense in this?
        Console.Write("foo");
    }
}
Seldon
quelle
70
Gibt es einen Grund, warum es nicht sollte ?
Jamiec
30
Aber wie die Antworten zeigen, hat es mehr Bedeutung als nur "tut nicht weh, also lass es zu". Dies ist ein Punkt, um solche Fragen zu stellen.
Seldon
8
+1 Frage klingt unschuldig genug, aber Antworten haben mir wirklich etwas Wertvolles
beigebracht
7
@Akash: Ohne zu fragen warum, werden wir nie besser werden.
Richard
7
@Akash: Das scheint eine hochkarätige elitäre Haltung zu sein. Die Leute haben immer Fragen, und wenn es keinen Grund gibt, zu fragen, warum, dann macht es keinen Sinn, SO zu haben. Diese Seite ist nicht so sehr dafür gedacht, dass Leute unsere unmittelbaren Probleme lösen (obwohl dies passiert), sondern um eine Sammlung von Fragen und Antworten bereitzustellen, die uns allen helfen, bessere Programmierer zu sein. SO ist für die Frage, warum! :-)
Richard

Antworten:

90

In dem von Ihnen angegebenen Kontext gibt es keine Bedeutung. Das Schreiben einer konstanten Zeichenfolge in die Konsole funktioniert überall im Programmablauf auf die gleiche Weise. 1

Stattdessen verwenden Sie sie normalerweise, um den Umfang einiger lokaler Variablen einzuschränken. Dies wird hier und hier weiter ausgeführt . Schauen Sie sich João Angelos Antwort und Chris Wallis 'Antwort für kurze Beispiele an. Ich glaube, dass dies auch für einige andere Sprachen mit C-Syntax gilt, jedoch nicht, dass sie für diese Frage relevant wären.


1 Es sei denn, Sie beschließen natürlich, lustig zu sein und Ihre eigene ConsoleKlasse mit einer Write()Methode zu erstellen , die etwas völlig Unerwartetes bewirkt.

BoltClock
quelle
24
Betreff: andere Sprachen: normalerweise, aber nicht immer. JavaScript ist eine bemerkenswerte Ausnahme. Durch das Deklarieren einer lokalen Variablen in einem bestimmten Block wird die Variable nicht auf den Block beschränkt.
Eric Lippert
@EricLippert: Verursacht das Deklarieren einer Variablen innerhalb eines Blocks in C #, dass die Variable aus Sicht der Laufzeit einen Gültigkeitsbereich hat? Nach allem, was ich sagen kann, sind die Lebensdauern von Variablen oft nicht durch Bereichsblöcke begrenzt. Dies ist in Projekten mit gemischten Sprachen zu beobachten, wenn das erste, was mit einer Variablen in einer Schleife gemacht wird, darin besteht, sie als outParameter an eine geschriebene Schnittstellenimplementierung zu übergeben in einer anderen Sprache, und diese Implementierung liest die Variable vor dem Schreiben.
Supercat
Und in C ++ ist es aufgrund von RAII anstelle von GC weitaus nützlicher.
Deduplikator
In C ++ verhält es sich ähnlich wie ein Try / Catch-Block, sodass Variablen und Klassen, die in diesem Bereich deklariert sind, vom Stapel genommen werden, wenn Sie diesen Bereich verlassen. Dies hilft, Namenskollisionen zu vermeiden und den Speicherbedarf der Funktion zu verringern. Außerdem werden diese Variablen aus der automatischen Vervollständigung des Code-Editors entfernt. Oft finde ich Try / Catch-Blöcke nützlicher.
Kit10
143

Dies { ... }hat zumindest den Nebeneffekt, dass ein neuer Bereich für lokale Variablen eingeführt wird.

Ich neige dazu, sie in switchAnweisungen zu verwenden, um für jeden Fall einen anderen Bereich bereitzustellen und auf diese Weise die Möglichkeit zu geben, lokale Variablen mit demselben Namen am nächstmöglichen Ort ihrer Verwendung zu definieren und auch anzuzeigen, dass sie nur auf der Ebene des Falls gültig sind.

João Angelo
quelle
6
Wenn Sie in Ihren Fällen Bereiche benötigen, sind diese zu groß! Methode extrahieren.
Jay Bazuzi
19
@ Jay Bazuzi, nur weil ich in mehr als einem Fall eine lokale Variable mit demselben Namen haben möchte, heißt das nicht, dass sie riesig sein müssen. Sie springen nur zu großen Schlussfolgerungen ... :)
João Angelo
Herzlichen Glückwunsch zu Ihrem Great Answer-Abzeichen! :)
BoltClock
1
@ BoltClock, danke, ich brauche nur noch ein paar Fragen {}, damit diese goldenen Abzeichen kommen ... :)
João Angelo
56

Es ist weniger ein Merkmal von C # als vielmehr ein logischer Nebeneffekt vieler C-Syntaxsprachen, die Klammern verwenden, um den Bereich zu definieren .

In Ihrem Beispiel haben die geschweiften Klammern überhaupt keine Auswirkung, aber im folgenden Code definieren sie den Umfang und damit die Sichtbarkeit einer Variablen:

Dies ist zulässig, da ich im ersten Block aus dem Gültigkeitsbereich herausfalle und im nächsten erneut definiert werde:

{
    {
        int i = 0;
    }

    {
        int i = 0;
    }
}

Dies ist nicht erlaubt, da ich aus dem Bereich gefallen bin und im äußeren Bereich nicht mehr sichtbar ist:

{
    {
        int i = 0;
    }

    i = 1;
}

Und so weiter und so fort.

Chris Wallis
quelle
1
Ich habe über Unterschiede in der Klammernomenklatur in verschiedenen englischen Geschmacksrichtungen gelesen, aber in welcher Geschmacksrichtung werden {}Klammern genannt?
BoltClock
Gute Frage! Ich glaube, ein Mentor von mir hat es vor einem Jahrzehnt in mein Gehirn gepflanzt. Ich sollte sie wahrscheinlich "geschweifte Klammern" oder "Klammern" nennen. Jeder für sich ... en.wikipedia.org/wiki/…
Chris Wallis
10
In meinem vocab '(' = Klammer '{' = Klammer, '[' = eckige Klammern
. Pb
Moment mal, ich würde sie eine geschweifte Klammer nennen, und Wikipedia enthält diese Benennung. Das Oxford English Dictionary definiert diese Verwendung der Klammer wie folgt: 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; In jedem Fall handelt es sich nicht um Klammern, sondern um eine geschweifte Klammer.
Dumbledad
IME, "geschweifte Klammern" und "eckige Klammern".
cp.engr
18

Ich betrachte {}als eine Aussage, die mehrere Aussagen enthalten kann.

Stellen Sie sich eine if-Anweisung vor, die aus einem booleschen Ausdruck gefolgt von einer Anweisung besteht. Das würde funktionieren:

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

Dies würde auch funktionieren:

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

Wenn ich mich nicht irre, wird dies als Blockanweisung bezeichnet.

Da {}kann andere Anweisungen enthalten, kann es auch andere enthalten {}. Der Bereich einer Variablen wird durch ihre übergeordnete Variable {}(Blockanweisung) definiert.

Der Punkt, den ich versuche zu machen, ist, dass dies {}nur eine Aussage ist, also erfordert es kein Wenn oder was auch immer ...

RBaarda
quelle
+1 Genau das sind geschweifte Klammern in C-Sprachen - eine sogenannte "zusammengesetzte Anweisung".
Michael Ekstrand
12

Die allgemeine Regel in C-Syntaxsprachen lautet: "Alles dazwischen { }sollte als einzelne Anweisung behandelt werden und kann überall dort eingesetzt werden, wo eine einzelne Anweisung dies könnte."

  • Nach einem if.
  • Nach einem for, whileoder do.
  • Überall im Code .

In jeder Hinsicht ist es so, wie es die Sprachgrammatik beinhaltet:

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

Das heißt, "eine Anweisung kann aus (verschiedenen Dingen) oder einer öffnenden Klammer bestehen, gefolgt von einer Anweisungsliste (die eine oder mehrere Anweisungen enthalten kann), gefolgt von einer geschlossenen Klammer". IE "a{ } Block kann jede Anweisung überall ersetzen". Einschließlich in der Mitte des Codes.

Wenn ein { }Block nirgendwo zugelassen wird, wo eine einzelne Anweisung hingehen kann, wäre die Sprachdefinition komplexer geworden .

Massimo
quelle
Jemand hat diese Antwort (nach 9 Jahren) nur erhöht, was eigentlich keine spezifische Antwort auf diese Frage war, sondern vielmehr eine allgemeine Diskussion. Es mag sehr wohl von der Sprache und den Bibliotheken abgelöst worden sein. Aber es war trotzdem ein Vergnügen, danke.
Massimo
1

Weil C ++ (und Java) Codeblöcke ohne vorhergehende Anweisung zuließen.

C ++ erlaubte es ihnen, weil C. es tat.

Man könnte sagen, dass alles auf die Tatsache zurückzuführen ist, dass das Design der US-Programmsprache (C-basiert) eher gewonnen hat als die europäische Programmsprache ( Modula-2) basiert).

(Steueranweisungen wirken sich auf eine einzelne Anweisung aus. Anweisungen können Gruppen sein, um neue Anweisungen zu erstellen.)

Ian Ringrose
quelle
Meinen Sie Modul2 oder Modula2?
Richard Ev
Dies ist in der Tat die richtige Antwort. Außerdem würde ich nur antworten: "Weil jede Computersprache dies tut."
Fattie
1
// if (a == b)
// if (a != b)
{
    // do something
}
user202448
quelle
0

1 Weil ... es den Bereichsbereich der Anweisung oder der Funktion beibehält, ist dies wirklich nützlich, um den großen Code zu verwalten.

{
    {
        // 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;
    }
}

Geben Sie hier die Bildbeschreibung ein

Raj
quelle
0

Sie haben gefragt, warum C # Codeblöcke ohne vorherige Anweisungen zulässt. Die Frage "warum" könnte auch als "was wären mögliche Vorteile dieses Konstrukts?" Interpretiert werden.

Persönlich verwende ich in C # anweisungslose Codeblöcke, bei denen die Lesbarkeit für andere Entwickler erheblich verbessert wird, wobei zu beachten ist, dass der Codeblock den Umfang lokaler Variablen einschränkt. Betrachten Sie beispielsweise das folgende Codefragment, das dank der zusätzlichen Codeblöcke viel einfacher zu lesen ist:

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

Mir ist bewusst, dass dies eleganter gelöst werden könnte, indem Methoden für jede Strukturebene verwendet werden. Denken Sie jedoch auch daran, dass Dinge wie Beispieldatensämaschinen normalerweise schnell sein müssen.

Obwohl der obige Code linear ausgeführt wird, stellt die Codestruktur die "reale" Struktur der Objekte dar, wodurch andere Entwickler das Verstehen, Verwalten und Erweitern erleichtern können.

Marco
quelle