Umgang mit lockiger Zahnspangensuppe

11

Ich habe jahrelang sowohl in C # als auch in VB.NET programmiert, aber hauptsächlich in VB. Ich mache eine Karriereverlagerung in Richtung C # und insgesamt mag ich C # besser.

Ein Problem, das ich jedoch habe, ist die geschweifte Zahnspangensuppe. In VB hat jedes Strukturschlüsselwort ein übereinstimmendes Schlüsselwort zum Schließen, zum Beispiel:

Namespace ...
    Class ...
        Function ...
            For ...
                Using ...
                    If ...
                        ...
                    End If
                    If ...
                        ...
                    End If
                End Using
            Next
        End Function
    End Class
End Namespace

Der gleiche in C # geschriebene Code ist sehr schwer zu lesen:

namespace ... {
    class ... {
        function ... {
            for ... {
                using ... {
                    if ... {
                        ...
                    }
                    if ... {
                        ...
                    }
                }
            }
            // wait... what level is this?
        }
    }
}

Da ich so an VB gewöhnt bin, frage ich mich, ob es eine Technik gibt, die von Programmierern im C-Stil verwendet wird, um die Lesbarkeit zu verbessern und sicherzustellen, dass Ihr Code im richtigen "Block" landet. Das obige Beispiel ist relativ einfach zu lesen, aber manchmal habe ich am Ende eines Codeteils 8 oder mehr Ebenen geschweifter Klammern, sodass ich mehrere Seiten nach oben scrollen muss, um herauszufinden, welche Klammer den Block beendet, an dem ich interessiert bin im.

JDB erinnert sich noch an Monica
quelle
83
Ich weiß, dass dies predigend klingen mag, und vielleicht haben Sie spezielle Bedingungen, die dies erfordern (weil ja, manchmal ist es notwendig - zum Glück sollten solche Zeiten selten sein), aber normalerweise "... 8 oder mehr Stufen von geschweiften Klammern, die mich zum Scrollen zwingen Wenn Sie mehrere Seiten nachschlagen, um herauszufinden, an welcher Klammer der Block endet, an dem ich interessiert bin, bedeutet dies, dass der Code ernsthaft überarbeitet und bereinigt werden muss.
FrustratedWithFormsDesigner
7
Eine Sache, die ich getan gesehen habe und die ich getan habe, ist am Ende einer geschweiften Klammer, ich werde einen Kommentar dazu hinzufügen. So etwas wie // End's using X statement.
PiousVenom
14
@FrustratedWithFormsDesigner ist genau richtig für die Tatsache, dass Ihr Kontrollfluss ein Chaos ist und überarbeitet werden muss. Das heißt, ich denke, Sie beschweren sich mehr über die geschweiften Klammern als über das Scoping, und ich würde sagen, Sie müssen sich nur daran gewöhnen. Das Erlernen einer Sprache mit einer deutlich anderen Syntax als Sie es gewohnt sind, sieht für eine Weile definitiv wie Suppe aus, aber mit etwas Übung geht das weg. Sie müssen sich nur anschnallen und handeln, bis Ihr Gehirn beginnt, die Syntax natürlicher zu verarbeiten.
Jimmy Hoffa
2
@FrustratedWithFormsDesigner - Ich muss viele COM-Objekte in einer COM-Interop-Situation bereinigen. Ich verwende die in diesem Artikel vorgeschlagene Technik: jake.ginnivan.net/vsto-com-interop . Dadurch entstehen leicht zwei oder drei Schichten. Wenn Sie die for-Schleife, die Funktion, die Klasse und den Namespace darüber stapeln (zusammen mit einer if-Anweisung), gelangen Sie leicht zu mehreren Ebenen von geschweiften Klammern.
JDB erinnert sich noch an Monica
5
@TyrionLannister - Und das können einige der schnellsten Kommentare sein, die nicht mehr mit dem übereinstimmen, zu dem sie gehören ... Ich denke, wenn ich so etwas haben würde, würde ich es vorziehen, wenn es automatisch generiert wird (auf dem Display) -Zeit nur, nicht beibehalten) von der IDE.
Uhrwerk-Muse

Antworten:

38

Setzen Sie Ihre beginnende geschweifte Klammer in den gleichen "Rang" wie Ihre endende:

namespace ... 
{
    class ... 
    {
        function ... 
        {
            for ... 
            {
                using ... 
                {
                    if ... 
                    {
                        ...
                    }
                    if ... 
                    {
                        ...
                    }
                }
            }
            // It's the `function` level!
        }
    }
}
Robert Harvey
quelle
15
Genau. Ägyptische Klammern bereiten mir Kopfschmerzen.
PiousVenom
8
Außerdem markieren die meisten IDEs (wahrscheinlich) den Partner einer Zahnspange, wenn Sie darauf klicken.
StuperUser
3
@ TyrionLannister: Danke, dass du mir endlich einen Begriff für diesen Stil gegeben hast! Ich hatte nie einen guten Namen für sie außer "falsch ausgerichteten Zahnspangen".
FrustratedWithFormsDesigner
3
@ Cyborgx37: Verfügt Ihre IDE über die Funktion "Gehe zu passender Klammer"? Normalerweise an eine Tastenkombination gebunden, die den Cursor automatisch auf die Klammer bewegt, die der aktuell markierten entspricht.
FrustratedWithFormsDesigner
3
Ich muss sagen, ich verstehe nicht, wie das alles einfacher macht. In beiden Fällen schauen Sie einfach auf der Einrückungsstufe der Klammer nach oben, bis Sie zu einem Schlüsselwort gelangen. Und mit all diesen zusätzlichen Zeilen müssen Sie jetzt weiter suchen.
Blorgbeard ist
14
  • Abhängig von Ihrer IDE: Setzen Sie den Cursor auf die Klammer zum Öffnen / Schließen, um sowohl diese als auch die entsprechende Klammer hervorzuheben.
  • Reduzieren Sie den Block und es zeigt Ihnen, wo er geöffnet / geschlossen wird.
  • Schreiben Sie kleinere Codeblöcke. Ernsthaft. Probieren Sie es aus Clean Codeund stoßen Sie nie wieder auf dieses Problem (und haben Sie mehr lesbaren / wartbaren Code).

Ein Hinweis, die folgende ist eine gültige c # -Syntax, die Ihrer speziellen Situation helfen könnte:

using (var type = new MyDisposable1())
using (var type2 = new MyDisposable2())
{
    /* do what you will with type2 and type2 */
}
Steven Evers
quelle
Die Jagd nach dem einzelnen hervorgehobenen Charakter hat mich dazu bewogen, diese Frage überhaupt zu stellen.
JDB erinnert sich noch an Monica
2
@ Cyborgx37: Daher Punkt 3. Wenn Ihr gesamter Codeblock auf den Bildschirm passt, müssen Sie nie jagen. In den meisten / allen Klassen, die ich schreibe, sind die einzigen Klammerpaare, die nicht auf den Bildschirm passen, Namespace / Klasse.
Steven Evers
Was Sie in den Punkten 1 und 2 vorschlagen, ist das, was ich jetzt mache ... aber dies erfordert, dass ich den Ort verlasse, an dem ich codiere, und meine Ansicht des Codes manipuliere, um herauszufinden, wo die nächste Zeile eingefügt werden soll. Punkt 3 ist gut aufgenommen, aber nicht immer möglich, insbesondere wenn Ihr Code mehrere Schichten von usingBlöcken erfordert (siehe jake.ginnivan.net/vsto-com-interop )
JDB erinnert sich immer noch an Monica
@ Cyborgx37: Siehe meine Bearbeitung.
Steven Evers
1
@ Cyborgx37 Wenn Sie eine Farbe auswählen, die sich von allem anderen abhebt (ich habe eine Weile lila Hintergrund und weißen Text verwendet, IIRC), müssen Sie nicht nach der passenden Zahnspange suchen - sie schreit Sie praktisch an "Ich bin HIER ! ".
Ein CVn
5

Eine übliche Konvention besteht darin, nach der schließenden Klammer einen Kommentar hinzuzufügen, um die Struktur anzugeben, die geschlossen wird:

if {
   ...
} // end if

while (condition) {
   ...
} // end while

usw. Ich habe mich nie auf diese Konvention erwärmt, aber einige Leute finden sie hilfreich.

John Bode
quelle
16
Ich habe Leute gesehen, die dies getan haben, und wenn sie den Anfang des Blocks tauschen / ändern (a whilein a ändern for, in ifAnweisungen tauschen ), erinnern sie sich fast NIE daran, die abschließenden Kommentare zu aktualisieren, was sie schlimmer als nutzlos macht. Diese Konvention wird wahrscheinlich nur dann nützlich sein, wenn Sie sich zwingen können, die Kommentare jedes Mal beizubehalten, wenn sich die Art der Übereinstimmung {ändert.
FrustratedWithFormsDesigner
Ja, ich habe einiges davon gemacht, aber es ist viel zusätzliche Arbeit (und Lärm). Ich hatte gehofft, dass es etwas Unkomplizierteres geben würde.
JDB erinnert sich noch an Monica
5
Kommentare sollten nur erklären, warum niemals was oder wie der Code beides tut. Wenn Sie sich auf Kommentare stützen, um einen der beiden zu erklären, ist der Code schwer zu lesen. Dies ist ein Zeichen dafür, dass der Code korrigiert und nicht kommentiert werden sollte.
Jimmy Hoffa
1
Ich frage mich daher, warum niemand einen Editor geschrieben hat, der diese Kommentare anzeigt, sie aber nicht in den Code aufnimmt.
Brendan Long
2
@ JimmyHoffa: Ich denke, eine bessere Regel für Kommentare ist, dass sie Klarheit schaffen sollten . Normalerweise bedeutet das, auf das "Warum" zu antworten, aber es kann auch andere Dinge bedeuten. Lassen Sie sich nicht so in ein Dogma verwickeln, dass es Sie davon abhält, Dinge zu tun, die tatsächlich helfen, z. B. gelegentlich einen Kommentar zu einer schließenden Klammer hinzuzufügen, die weit von ihrer öffnenden Klammer entfernt ist.
Bryan Oakley
5

Wenn es schwierig wird, Zahnspangen in einem beliebigen Stil zu finden, bedeutet dies im Allgemeinen wahrscheinlich, dass die Methode zu lang ist und neu berücksichtigt werden sollte.

MaximR
quelle
5

Ich denke, Sie müssen es mit den Zahnspangen aushalten. Irgendwann werden sie für Sie zur zweiten Natur und Sie werden sich fragen, wie Sie jemals ohne sie gelebt haben.

Stellen Sie jedoch sicher, dass sie entsprechend eingerückt sind und dass einige Abstandskonventionen eingehalten werden (egal welche).

MrFox
quelle
Ein Jahr später, und dieser Rat klingt wahr. :)
JDB erinnert sich noch an Monica
4

Ich entferne zwei Verschachtelungsebenen, indem ich den Namespace und die Klassenbereiche horizontal reduziere. Beachten Sie, dass die Methoden bündig mit dem linken Bildschirmrand abschließen. Ich sehe keinen Sinn darin, in jeder Datei zwei Einrückungsstufen zu verlieren.

Danach ist es selten, dass Sie jemals mehr als 4 Ebenen tief verschachtelt haben.

namespace FooNameSpace {
class Foo {

public void bar()
{
    while(true)
    {
        while(true)
        {
            break;
        }
    }
}

public void fooBar()
{
    foreach(var item in FooList)
    {
        foreach(var b in item.Bars)
        {
            if(b.IsReady)
            {
                bar();
            }
            bar();
        }
        bar();
    }
}

}}//end class, namespace
mike30
quelle
Ich mag diese Idee, aber Visual Studio scheint sie nicht zu unterstützen (zumindest 2008. Wir aktualisieren bis Ende des Jahres auf 2012, also hoffen
wir
@ Cyborgx37. Ich bearbeite den Text extern in VIM, damit es kein Problem ist. Führen Sie in Visual Studio jedoch Folgendes aus: Strg + A, und klicken Sie dann auf die Schaltfläche "Weniger einrücken". Tun Sie dies nur für neue Dateien. Kümmern Sie sich nicht um vorhandene Dateien, da dies die Diff-Vergleiche in der Quellcodeverwaltung durcheinander bringt.
Mike30
Wenn Sie schließende Klammern / Klammern eingeben, wird ein automatisches Format von VS initiiert. Sie können jedoch jederzeit STRG + z drücken, um den Vorschlag abzulehnen.
Alex In Paris
1

Ich habe kürzlich beschlossen, zwei Regeln für Flusskontrollkonstrukte zu formalisieren, die im Grunde so aussehen:

  • Sie sollten nur die erforderlichen Code-Flow-Konstrukte haben
  • Sie sollten die Code-Flow-Konstrukte so klein wie möglich machen

Aus genau den Gründen, die Sie erwähnt haben und die Sie genau kennen, halte ich dies für gute Regeln. Es gibt ein paar einfache Techniken, mit denen Sie sie erreichen können:

  • Beenden Sie den Bereich so bald wie möglich (dies umfasst sowohl den Umfang der Schleifen als auch die Funktionen).
  • Achten Sie auf andere Faktoren, die durch Beenden der Funktion aus dem vorhergehenden if gemildert werden könnten, und wenden Sie die erwähnte Technik zum Beenden des Bereichs an
  • Kehren Sie Ihre bedingten Prüfungen um, wenn der Code innerhalb eines if größer ist als der außerhalb
  • Faktorcode innerhalb einer Schleife wird zu einer anderen Methode ausgegeben, wenn die Größe der Schleife zunimmt, um den Rest der Methode zu verdecken
  • Achten Sie auf Bereiche, die nur einen anderen Bereich enthalten, z. B. eine Funktion, deren gesamter Bereich von einem if mit nichts außerhalb des if gefüllt ist

Ich habe hier Beispiele aufgeführt, wie das Nichtbefolgen dieser Anweisungen dazu führen kann, dass Sie das tun, was Sie gesagt haben, und Code in den falschen Codeblock einfügen. Dies ist schlecht und eine einfache Ursache für das Auftreten von Fehlern während der Wartung.

Jimmy Hoffa
quelle
Danke, es könnte ein oder zwei Blöcke geben, die ich umgestalten könnte. Es wird helfen, aber es ist schwierig, mehrere verschachtelte usingBlöcke umzugestalten .
JDB erinnert sich noch an Monica
@ Cyborgx37, das tatsächlich Blöcke verwendet, kann eingefügt werden, wenn sie verschachtelt sind und Bereiche erfüllen. Schauen Sie hier stackoverflow.com/questions/1329739/…. Es funktioniert im Grunde wie einzeilige Flusssteuerungskonstrukte, wie Sie können, wenn (true) doSomething (); Sie können auch if (true) if (SomethingElse) if (otherThings) {doThis (); TU das(); mach was auch immer(); } und das Wenn nisten wie erwartet (SCHREIBEN SIE KEINEN CODE, WIE DAS FÜR DIE LIEBE GOTTES, TUN SIE DAS NUR MIT VERWENDUNGEN UND NICHTS ANDEREM heh)
Jimmy Hoffa
Ja, ich weiß, wie man Blöcke verschachtelt, aber das funktioniert nur, wenn Sie eine einzelne Zeile darunter haben. In den meisten meiner Codes ist das nicht der Fall.
Insgesamt immer
@ Cyborgx37 Ja, mir ist klar, dass die Scope-Verschachtelung nur funktioniert, wenn Sie keine zusätzlichen Bits haben. Das heißt, gibt es ein Muster für die Art Ihrer Verwendung? Wäre es vielleicht sinnvoll, etwas davon in den Konstruktor zu verschieben, wenn es oben ist, oder die Entsorgung, wenn es unten ist? Das ist, wenn es gemustert ist; Vermutlich liegt es daran, dass Sie dies als Problem angesprochen haben, sodass Sie wahrscheinlich häufig auf Nester in Ihrem Code stoßen.
Jimmy Hoffa
Ich habe tatsächlich mit der Arbeit an einer Factory-Pattern-Implementierung begonnen, die COM-Objekte in eine "AutoCleanup" -Klasse einschließt. Ich verwende dann eine einzelne usingAnweisung für die Factory-Klasse und wenn sie entsorgt wird, werden automatisch alle abgeschlossenen Klassen entsorgt. Es funktioniert bisher gut und hat die Anzahl der usingAnweisungen in meinem Code erheblich reduziert .
JDB erinnert sich noch an Monica
1

Dies ist leider eine der ältesten Ursachen für Kriegsführung im Computer. Von beiden Seiten können vernünftige Argumente vorgebracht werden (bessere vertikale Immobilienökonomie im Vergleich zu einer einfacheren Möglichkeit, die öffnende Klammer visuell mit der schließenden Klammer abzugleichen), aber in Wirklichkeit wird ein einfacher Quellcode-Formatierer alles für Sie lösen. In MS Visual C # ist eine integriert, die gut funktioniert.

Seien Sie jedoch gewarnt, dass Sie, wenn Sie als Teil eines Teams arbeiten, die von diesem Team verwendeten Konventionen einhalten müssen. Es lohnt sich daher, sich mit beiden Stilen vertraut zu machen und nicht religiös zu werden.

Konzentrieren Sie sich also auf jeden Fall auf den Stil, der Ihnen das Lernen erleichtert, aber behalten Sie den anderen im Auge, während Sie gerade dabei sind, und Sie werden es gut machen.

Maximus Minimus
quelle
1
Ich bin nicht sicher, ob es der Standardformatierer oder etwas in ReSharper ist, aber als ich C # verwendet habe, hatten wir eine Option festgelegt, die den Code beim Einchecken neu formatierte. Auf diese Weise können Sie den Code formatieren, wie Sie möchten, während Sie damit arbeiten, aber er wird beim Einchecken auf "Projektstandard" neu formatiert. Ich denke, der einzige wirkliche Formatierungsstandard, den wir hatten, war die Verwendung von Leerzeichen anstelle von Tabulatoren.
TMN
1

Verwenden Sie Resharper, um Möglichkeiten zur Reduzierung der Verschachtelung zu empfehlen. Lesen Sie auch Bob Martins Buch Clean Code , in dem betont wird, dass eine Funktion nur eines tun sollte und daher jede Funktion nur ein halbes Dutzend Zeilen lang sein sollte, damit Sie sich nicht um so viele Verschachtelungsebenen kümmern müssen.

Lorddev
quelle
1

Es gibt ein Add-On zum Editor, das Ihnen bei folgenden Aufgaben helfen kann: C # Outline .

Das Add-On erweitert den VS20xx-Editor für C # um Funktionen zum Reduzieren, Erweitern und Hervorheben verschachtelter Codeblöcke. Diese Funktionen ermöglichen das einfachere Bearbeiten und Lesen verschachtelter Inhalte von Codeblöcken wie if, while usw.

Keine Chance
quelle
0

Wenn Sie Ihren Code in Visual Studio schreiben, gibt es auch ein Plugin, das Ihnen vertikale Punkte zwischen dem Anfang und dem Ende jeder von Ihnen erstellten Struktur anzeigt.

Aber insgesamt denke ich, dass es nur einige Zeit dauern wird, bis Sie an die "Curly-Braces-Suppe" gewöhnt sind. (Übrigens mag ich diesen Ausdruck wirklich. Klingt ein bisschen wie ein Episodenname für die Urknalltheorie)

mhr
quelle
0

Einzug sagt Ihnen, wo Sie sich befinden, in beiden Syntaxstilen. Wenn Sie entweder ein VB-Programm oder ein C # -Programm in eine einzelne Zeile schreiben, können Sie in der verschachtelten Syntax bald nicht mehr erkennen, wo Sie sich befinden. Die Maschine analysiert die Blockendphrasen oder geschweiften Klammern, aber Menschen brauchen Einrückungen.

Blockendphrasen stammen aus einer Ära von Lochkarten und Papierbändern, als die Programmierung viel weniger interaktiv und visuell war. Oder wirklich überhaupt nicht interaktiv. Es war schwierig, Programme einzugeben, und deshalb brauchten Programmierer Compiler, die sich mit Syntaxanalyse und Fehlerbehebung auskennen.

In dieser vergangenen Ära bestand der Zyklus zum Bearbeiten, Kompilieren und Ausführen möglicherweise darin, Lochkarten mit einem Kartenstempel vorzubereiten und sich dann an ein Fenster für die Auftragsübermittlung zu stellen, in dem ein Angestellter die Lochkarten nahm und sie an die Maschine übermittelte. Später sammelte der Programmierer die Ausgabe (auf Papier gedruckt) in einem anderen Fenster. Wenn das Programm Fehler hätte, würde die Ausgabe nur aus der Compiler-Diagnose bestehen. Wenn die Bearbeitungszeiten lang sind, sind die zusätzlichen Kosten für die Eingabe end ifanstelle von nur )gerechtfertigt, wenn dies zur Verbesserung der Diagnosequalität beiträgt, da der Programmierer so viele Fehler wie möglich in einer einzigen Iteration korrigieren muss, um die Anzahl der Zeitverschwendung zu verringern Iterationen durch das Jobübermittlungsfenster.

Wenn eine schließende geschweifte Klammer fehlt, ist es schwer zu sagen, welche offene Klammer die nicht geschlossene ist. (Der Compiler muss möglicherweise Einrückungen analysieren, um eine fundierte Vermutung anzustellen.) Wenn Sie eine schließende Klammer innerhalb einer Funktion löschen, sieht es so aus, als ob der gesamte Rest der Datei Teil dieser Funktion ist, was zu einer Reihe nicht hilfreicher Fehlermeldungen führt. Wenn Sie hingegen über eine end functionSyntax verfügen , kann der Compiler ableiten, wo die fehlerhafte Funktion endet, die nachfolgenden Funktionen ordnungsgemäß wiederherstellen und analysieren, sodass Sie gegebenenfalls zusätzliche Diagnosen erhalten, die von Bedeutung sind.

Wenn Sie in einem Code-fähigen Texteditor arbeiten, der Ihren Code automatisch einrückt und einfärbt, gelten auf einem hochauflösenden Bildschirm, auf dem Sie 60 oder mehr Zeilen sehen, die Argumente für diese Art von ungeschickten Sprachen nicht mehr. Sie können Programme schrittweise so schnell bearbeiten und neu erstellen, dass Sie jeweils nur einen Fehler behandeln können. Darüber hinaus können Sie das Auftreten solcher Verschachtelungsfehler reduzieren, indem Sie große Teile des Programms gleichzeitig auf dem Bildschirm anzeigen und die richtige Einrückung beibehalten. Und ein guter Programmier-Texteditor kennzeichnet während der Eingabe sogar einige Arten von Syntaxfehlern. Darüber hinaus gibt es faltbare Editoren, die die Blöcke eines Programms basierend auf seiner Syntax reduzieren und so eine "umrissartige" Ansicht seiner Struktur geben.

Lisp verwendete von Anfang an Klammern, und vielleicht, nicht zufällig, leisteten Lisp-Hacker Pionierarbeit beim Programmieren als interaktives Erlebnis, indem sie Systeme erstellten, die Programme in kleinen Blöcken (Ausdrücken) akzeptierten.

Tatsächlich benötigen Sie überhaupt keine Endsymbole, wie die Python-Sprache zeigt. Die identation kann nur sein , die Struktur. Menschen verwenden bereits Einrückungen, um die Struktur des Codes selbst in Sprachen zu erfassen, in denen die Maschine auf Endsymbole oder -phrasen angewiesen ist.

Kaz
quelle
-1

Wenn Sie eine IDE verwenden, drücken Sie einfach Crtl+ k+ Dund die IDE erledigt den Rest der Arbeit.

Jagz W.
quelle
Welche IDE-Eclipse verwendet Strg-Shift-I zum Einrücken und Strg-Shift-F zum Formatieren
Ratschenfreak
Check in Visual Studio
Jagz W