Verwendet noch jemand [goto] in C # und wenn ja, warum? [geschlossen]

104

Ich habe mich gefragt, ob noch jemand die Schlüsselwortsyntax "goto" in C # verwendet und welche möglichen Gründe dafür vorliegen.

Ich neige dazu, Aussagen, die dazu führen, dass der Leser durch den Code springt, als schlechte Praxis anzusehen, habe mich aber gefragt, ob es glaubwürdige Szenarien für die Verwendung einer solchen Syntax gibt.

Gehe zu Schlüsselwortdefinition

Brian Scott
quelle
3
was meinst du mit "still"? Gab es eine Zeitspanne, in der die Leute es die ganze Zeit benutzt haben [in c #]?
Massiv
4
@Massif: "still" sollte die moderne Meinung über die Verwendung von "goto" als Auftakt zum Spaghetti-Code und mangelnde Lesbarkeit im Quellcode betonen. Sehr selten sehen Sie Codebeispiele, einschließlich dieses speziellen Schlüsselworts, weshalb ich überhaupt daran interessiert war, nachzufragen.
Brian Scott
50
Wenn der Leser den Code "herumspringt", ist dies eine schlechte Praxis. Vermeiden Sie dann auch "brechen", "fortfahren", "werfen" und "zurückkehren"? Sie alle verursachen einen Zweig im Kontrollfluss, manchmal einen nicht lokalen Zweig. "Throw" sagt dir nicht einmal, wohin es geht, im Gegensatz zu goto.
Eric Lippert
2
Ich benutze goto, um eine Schleife zu brechen und zur Startanweisung gemäß der spezifischen Bedingung zurückzukehren
Nitin Sawant
3
Ich mag goto. Ich habe versucht, es zu vermeiden, weil die Leute sagten, es zu vermeiden, weil es das Lesen von Code erschwert. Nachdem ich Assemblersprache und Verzweigungsanweisungen gelernt habe, denke ich, dass es manchmal Zeiten gibt, in denen der Code lesbarer wird. Ich denke, dass mehrere Verwendungen in einer Methode und ein zu weites Springen im Code mehr schaden als nützen können. Aber wenn Sie denken, ein Goto würde hier gut funktionieren, sollte ein einfaches Goto hin und wieder nicht dazu führen, dass Sie sich aus dem Weg gehen, um es zu vermeiden, nur weil der allgemeine Konsens darin besteht, es zu vermeiden.
eaglei22

Antworten:

93

Es gibt einige (seltene) Fälle, in denen goto die Lesbarkeit verbessern kann. In der Dokumentation, mit der Sie verlinkt haben, sind zwei Beispiele aufgeführt:

Eine häufige Verwendung von goto besteht darin, die Kontrolle auf ein bestimmtes Switch-Case-Label oder das Standard-Label in einer switch-Anweisung zu übertragen.

Die goto-Anweisung ist auch nützlich, um tief verschachtelte Schleifen zu verlassen.

Hier ist ein Beispiel für letzteres:

for (...) {
    for (...) {
        ...
        if (something)
            goto end_of_loop;
    }
}

end_of_loop:

Natürlich gibt es auch andere Möglichkeiten, um dieses Problem zu umgehen, z. B. das Umgestalten des Codes in eine Funktion, die Verwendung eines Dummy-Blocks usw. ( Einzelheiten finden Sie in dieser Frage ). Als Randnotiz beschlossen die Java-Sprachdesigner, goto vollständig zu verbieten und stattdessen eine beschriftete break- Anweisung einzuführen .

Heinzi
quelle
47
Normalerweise würde ich versuchen , dies zu überarbeiten, um die Schleifen in eine separate Methode zu setzen, von der ich gerade zurückkehren könnte ...
Jon Skeet
2
@ Heinzi - Ich habe nicht gesehen, dass Goto gerechtfertigt ist. Wie Jon sagt, wenn es "gerechtfertigt" ist, bittet der Code darum, überarbeitet zu werden.
Manojlds
29
beschriftete Pause, nur eine längere Art, goto zu sagen, weil es das gleiche verdammte Ding macht ...
Jesus Ramos
20
@ Jesus aber dann mit goto kannst du überall hingehen. Die beschriftete Unterbrechung stellt sicher, dass Sie sich gerade außerhalb der Schleife befinden.
Mihsathe
1
Wenn Sie nicht abenteuerlustig sind und goto mit einer Adresse verwenden (ich habe es schon einmal gesehen), wird dieses Problem gemildert. Und ich bezweifle, dass jemand Umleitungs-Hooks in Ihrem C # - und Java-Code verwendet, um goto-Anweisungen auszunutzen.
Jesus Ramos
64

Ich erinnere mich an diesen Teil

switch (a)     
{ 
    case 3: 
        b = 7;
        // We want to drop through into case 4, but C# doesn't let us
    case 4: 
        c = 3;
        break; 
    default: 
        b = 2;
        c = 4;
        break; 
}

Zu so etwas

switch (a)     
{
    case 3: 
        b = 7;
        goto case 4;    
    case 4: 
        c = 3;
        break;     
    default: 
        b = 2;
        c = 4;
        break;
}

Siehe dies

V4Vendetta
quelle
17
Ich sehe dies tatsächlich als den zutreffendsten Grund, [goto] bisher zu verwenden. Zumindest in diesem Szenario erhöht es die Lesbarkeit für Programmierer, die nicht wissen, dass Fälle ohne break-Anweisung ineinander fallen.
Brian Scott
11
@ Brian Scott, V4Vendetta. Sofern ich mich nicht irre, wird die erste Anweisung nicht in C # kompiliert. Das würde das Verständnis des Programmierers verbessern.
Jodrell
2
V4Vendetta, warum haben Sie beim ersten Code-Snippet eine Unterbrechung eingefügt ...? Es war besser, es ohne Pause zu zeigen, sonst machen die beiden Schnipsel unterschiedliche Dinge. Der Grund, warum Sie das Goto im zweiten Beispiel benötigen, liegt genau darin, dass das erste nicht in C # kompiliert wird (wie in C).
Stephen Holt
23

Ich verwende es in Eduasync ausgiebig , um die Art von Code zu zeigen, die der Compiler für Sie generiert, wenn Sie in C # 5 asynchrone Methoden verwenden. In Iteratorblöcken wird dasselbe angezeigt.

Im "normalen" Code kann ich mich jedoch nicht erinnern, wann ich ihn das letzte Mal verwendet habe ...

Jon Skeet
quelle
1
Können Sie ein kleines Beispiel dafür geben, warum dieser Ansatz bevorzugt wurde oder war es einfach eine persönliche Präferenz?
Brian Scott
1
@ Brian: Es ist nicht wirklich klar, was du meinst. Eduasync zeigt den äquivalenten C # -Code zu dem, was der Compiler für Sie tut - und er generiert Code, der goto effektiv verwendet ...
Jon Skeet
9

goto ist ideal, um aus vielen Schleifen auszubrechen, in denen break nicht gut funktionieren würde (z. B. unter Fehlerbedingungen), und wie Kragen sagte, wird goto vom Compiler verwendet, um switch-Anweisungen und einige andere Dinge zu generieren.

Jesus Ramos
quelle
7
Sicherlich sind "break" / "continue" bessere Ansätze für das Loop-Management, als dass der Code-Editor im Quellcode herumspringen muss, um zu verstehen, wo der nächste Schritt stattfindet.
Brian Scott
6
Nicht, wenn Sie verschachtelte Schleifen haben.
Jesus Ramos
1
ok, ich kann das als gültiges Szenario sehen.
Brian Scott
1
In einem Fehlerzustand sollten Sie eine Ausnahme auslösen.
Jodrell
6
Wenn Sie den Fehler ausnahmslos intern behandeln möchten, ist dies eine gültige Methode.
Jesus Ramos
8

Ich erinnere mich nicht, jemals benutzt zu haben goto. Aber vielleicht verbessert es die Absicht einer Forever-Schleife, die Sie wirklich nie beenden möchten (nein break, aber Sie können immer noch returnoder throw):

forever: {
  // ...
  goto forever;
}

Andererseits sollte ein einfaches while (true)ausreichen ...

Sie können es auch in einer Situation verwenden, in der die erste Iteration einer Schleife in der Mitte der Schleife beginnen soll: Hier finden Sie ein Beispiel.

Jordão
quelle
Die verknüpfte Antwort enthält eine "interessante" Verwendung von goto.. und while(true) {..}ist keine interessante Verwendung ..
user2864740
5

Der Compiler verwendet gotoAnweisungen in verschiedenen Teilen des generierten Codes, beispielsweise in generierten Iteratorblocktypen (generiert bei Verwendung des yield returnSchlüsselworts - ich bin mir ziemlich sicher, dass die generierten XML-Serialisierungstypen auch gotoirgendwo einige Anweisungen enthalten.

Siehe Iteratorblock Implementierungsdetails: automatisch generierte Zustandsmaschinen für einige weitere Details, warum / wie die C # -Compiler Griffe dies.

Anders als generierter Code gibt es keinen guten Grund, eine gotoAnweisung in normalem Code zu verwenden - dies erschwert das Verständnis des Codes und ist daher fehleranfälliger. Andererseits kann die Verwendung von gotoAnweisungen in einem solchen generierten Code den Generierungsprozess vereinfachen und ist normalerweise in Ordnung, da niemand den generierten Code lesen (oder ändern) wird und keine Möglichkeit besteht, dass Fehler gemacht werden, weil eine Maschine schreibt.

Siehe Go-to-Anweisung, die als schädlich für ein Argument gegen gotosowie ein klassisches Stück Programmiergeschichte angesehen wird.

Justin
quelle
4
Das ist dumm: Es gibt mehrere Fälle, in denen goto nützlich ist, wie andere Antworten zeigen. Entweder Sie reiben sie explizit oder Sie sagen nur "es ist falsch", na ja, falsch.
o0 '.
@Lohoris Ich kaufe es nicht - jedes Beispiel, bei dem goto "die Lesbarkeit verbessert" (einschließlich der Antworten hier), wäre nach einigem einfachen Refactoring weitaus besser lesbar.
Justin
3
@ Justin nein, manchmal sind verschachtelte Schleifen nur die natürlichste Art, etwas zu tun, zum Beispiel, wenn Sie ein Array von Arrays durchlaufen.
o0 '.
6
@ Justin es ist nicht immer klarer, es in eine Funktion zu haben. Sie erzwingen etwas (haben eine Funktion), nur um etwas zu vermeiden, das Sie religiös hassen (mit einem goto). Eindeutiger Hinweis darauf, dass etwas falsch gemacht wurde.
o0 '.
3
@ Justin Functions-Aufrufe haben Overhead. gotonicht. Etwas zu beachten.
Dan Bechard
2

Der Prozessor implementiert mindestens eine Sprunganweisung, und ich bin sicher, dass viele Anweisungen diese in ihrer Implementierung oder Interpretation verwenden.

Eines der guten Dinge bei der Verwendung einer Sprache der 3. oder 4. Generation ist, dass diese physischen Details von uns weg abstrahiert werden. Obwohl wir uns des Gesetzes der undichten Abstraktion bewusst sein sollten, denke ich, dass wir unsere Werkzeuge auch so verwenden sollten, wie sie beabsichtigt sind ( sorry ). Wenn ich Code schreiben würde und eine gotogute Idee wäre, wäre es Zeit für eine Umgestaltung. Der Zweck einer strukturierten Sprache besteht darin, diese "Sprünge" zu vermeiden und einen logischen Ablauf in unserem Engineering zu erzeugen.

Ich sollte die Verwendung von vermeiden, breakaber ich kann den Leistungsvorteil nicht übersehen. Wenn ich jedoch verschachtelte Schleifen habe, die sich gegenseitig benötigen, ist breakes Zeit für eine Umgestaltung.

Wenn jemand eine Verwendung vorschlagen kann, gotodie besser erscheint als eine Umgestaltung, werde ich meine Antwort gerne zurückziehen.

Ich hoffe, ich bin nicht schuldig, hier zum " Fahrradschuppen " zu eilen. Wie Kragen sagt, ist gut genug für Dijkstra gut genug für mich.

Jodrell
quelle
1
Nehmen Sie ein dynamicObjekt und gehen Sie zu seinem Objektdiagramm, das mehrere Wörterbücher enthält, um zu den Werten zu gelangen, die ich benötige. Es ist nicht sinnvoll, Methoden zu verwenden, die einen Parameter haben und dynamicdennoch eine genaue Objektform erwarten. Mit goto können Sie mehrere Ebenen aufbrechen und weiter durch eine Sammlung dieser Objekte gehen. [Ich
besitze
-6

Springen ist nie besser. Und fahren Sie fort, brechen Sie (außer in Schalter / Fall), (mehrfach) zurück und werfen Sie auch auf das kleinste Minimum. Sie möchten niemals aus der Mitte von Nestschleifen entkommen. Sie möchten immer, dass die Schleifensteuerungsanweisungen die gesamte Schleifensteuerung haben. Das Einrücken enthält Informationen, und alle diese Anweisungen werfen diese Informationen weg. Sie können auch alle Einrückungen entfernen.

Kirk Augustin
quelle
10
Sie möchten aus einer Schleife ausbrechen, wenn es keinen Sinn macht, die Ausführung der Schleife beizubehalten. Andernfalls verschwenden Sie ohne Grund mehr Verarbeitungszeit in längeren Schleifen.
Skuld
12
@ Kirk, das klingt eher nach einer Meinung als nach etwas Quantitativem?
Brian Scott