まだC#で​​[goto]を使用している人はいますか。[閉まっている]


104

まだC#で​​「goto」キーワード構文を使用している人がいるかどうか、その理由は何ですか。

私は、読者にコードをジャンプさせるようなステートメントを悪い習慣と見なす傾向がありますが、そのような構文を使用するための信頼できるシナリオがあるかどうか疑問に思いましたか?

キーワード定義に移動


3
「まだ」とはどういう意味ですか?[c#で]人々がずっとそれを使用した期間がありましたか?
Massif 2011

4
@Massif: "still"は、スパゲッティコードの前置きとしての "goto"の使用とソースコードの読みやすさの欠如についての現代的な意見を強調することを目的としています。非常にまれに、この特定のキーワードを含むコード例が表示されないので、そもそも私が質問に興味を持っていました。
ブライアンスコット

50
読者がコードを「飛び回る」ことが悪い習慣である場合、「ブレーク」、「続行」、「スロー」、および「リターン」も避けますか?これらはすべて、制御フローに分岐を引き起こし、時には非ローカル分岐を引き起こします。gothとは異なり、「throw」はそれがどこへ向かっているのかさえ教えてくれません。
Eric Lippert

2
私が使用してgotoループを切断して、特定の条件に応じて文を開始するに戻って
ニティンSawant

3
後藤が好きです。コードを読みづらくするので避けたがる傾向があるので避けようとしました。アセンブリ言語と分岐ステートメントを学んだので、ときどきコードが読みやすくなることがあります。私は、1つのメソッドで複数の使用法があり、コード内であまりにも下にジャンプすると、良いというよりは害をもたらす可能性があると思います。しかし、gotoがここでうまく機能すると考えている場合、単純なgotoがたまに回避しないといけないということはありません。
eaglei22、2018

回答:


93

gotoが実際に読みやすさを改善できる(まれな)ケースがいくつかあります。実際、リンクしたドキュメントには2つの例がリストされています。

gotoの一般的な用途は、switchステートメントの特定のswitch-caseラベルまたはデフォルトラベルに制御を移すことです。

gotoステートメントは、深くネストされたループから抜け出すのにも役立ちます。

後者の例を次に示します。

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

end_of_loop:

もちろん、この問題には、コードを関数にリファクタリングする、その周りにダミーブロックを使用するなど、他の方法もあります(詳細については、この質問を参照してください)。補足として、Java言語の設計者はgotoを完全に禁止し、代わりにラベル付きのbreakステートメントを導入することを決定しました。


47
通常、私は思いますしてみてください ...私はちょうどから返すことができ、別の方法でループを置くために、これをリファクタリングする
ジョンスキート

2
@Heinzi-gotoが正当化されるのを見たことがありません。Jonが言うように、「保証」されている場合、コードはリファクタリングを要求されます。
manojlds

29
ラベルされたブレーク、それは同じfreakinののことを行うためのgotoを言うだけの長い道....
イエス・ラモス

20
@イエスですが、gotoを使用すると、どこにでも移動できます。ラベル付きのブレークにより、ループのすぐ外側に移動できます。
mihsathe

1
あなたが冒険的で、アドレスでgotoを使用している場合を除いて(以前にそれが実行されたのを見たことがあります)、その問題は軽減されます。そして、誰かがC#およびJavaコードで迂回フックを使用してgotoステートメントを悪用しているのではないかと思います。
ジーザスラモス、2011

65

この部分を覚えています

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

このようなものに

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

これを参照


17
私は実際にこれを[goto]を使用する最も有効な理由だと考えています。少なくともこのシナリオでは、breakステートメントを使用せずにケースが相互にドロップすることをプログラマが知らないため、読みやすさが向上します。
ブライアンスコット

11
@ブライアン・スコット、V4Vendetta。私が間違っていない限り、最初のステートメントはC#でコンパイルされません。それはプログラマーの理解を助けるでしょう。
Jodrell、2011

2
V4Vendettaなぜ最初のコードスニペットにブレークを挿入したのですか...?改行せずに表示した方がよいでしょう。さもなければ、2つのスニペットは異なることを行います。2番目の例でgotoが必要なのは、最初の例がC#でコンパイルされない(Cの場合のように)ためです。
Stephen Holt、

23

Eduasyncで幅広く使用して、C#5で非同期メソッドを使用するときにコンパイラーが生成するコードの種類を示しています。イテレーターブロックでも同じことがわかります。

「通常の」コードでは、最後に使用したのが思い出せません...


1
このアプローチが好まれた理由、または単に個人的な好みだった理由の小さな例を提供できますか?
ブライアンスコット

1
@ブライアン:どういう意味かよくわからない。Eduasyncは、コンパイラーがあなたに代わって行うのと同等のC#コードを示します-そして、gotoを効果的に使用するコードを生成します...
Jon Skeet

9

gotoは、breakがうまく機能しない多くのループ(エラー条件など)から抜け出すのに最適です。Kragenが言ったように、gotoはコンパイラーがswitch文やその他のことを生成するためにも使用されます。


7
確かに「ブレーク」/「続行」は、次のステップが発生する場所を理解しようとしてコードエディターにソースコードをジャンプするように要求するのではなく、ループ管理へのより良いアプローチですか?
ブライアンスコット

6
ネストされたループがある場合はそうではありません。
ジーザスラモス

1
わかりました、これは有効なシナリオと見なすことができます。
ブライアンスコット

1
エラー状態では、例外のスローを検討する必要があります。
Jodrell、2011

6
エラーを例外なく内部で処理したい場合、これは有効な方法です。
ジーザスラモス

8

を使用したことを覚えていませんgoto。しかし、多分それはあなたが本当に終了したくない永久ループの意図を改善します(いいえbreak、しかしあなたはまだreturnまたはすることができますthrow):

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

もう一度、シンプルwhile (true)で十分です...

また、ループの最初の反復をループの途中から開始したい場合に使用できます。例については、こちらご覧ください


リンク答えはの「面白い」の使用が含まれていますgoto。..とwhile(true) {..}..興味深い使用ではありません
user2864740

5

コンパイラはgoto、生成されたコードのさまざまな部分でステートメントを使用します。たとえば、生成されたイテレータブロックタイプ(yield returnキーワードを使用すると生成されます)-生成されたXMLシリアル化タイプにも、gotoどこかにいくつかのステートメントがあることは確かです。

参照イテレータブロックの実装の詳細を:自動生成されたステートマシンをなぜ/どのようにC#コンパイラハンドルこの上でいくつかの詳細については。

生成されたコード以外にgoto、通常のコードでステートメントを使用する十分な理由はありません。コードを理解することが難しくなり、結果としてエラーが発生しやすくなります。一方、gotoこのように生成されたコードでステートメントを使用すると、生成プロセスが簡略化され、通常は問題ありません。生成されたコードをだれも読み取ったり(または変更したり)したり、マシンが書き込みを行っているためにエラーが発生する可能性がないからです。

古典的なプログラミング履歴だけでなく、反対する議論のために有害であると考えられるGo-toステ​​ートメントを参照してくださいgoto


4
これはばかげています。他の回答で示されているように、gotoが役立つ場合がいくつかあります。それらを明示的にrubutするか、単に「それは間違っている」と言うのは、まあ、間違っています。
o0 '。

@Lohoris私はそれを購入していません-gotoが "読みやすさを向上させる"(ここでの回答を含む)の例は、単純なリファクタリングの後ではるかに読みやすくなっています。
ジャスティン

3
@Justinいいえ、ネストされたループは、たとえば配列の配列をトラバースする場合など、何かを行う最も自然な方法です。
o0 '。

6
@ジャスティンは、それを関数に入れることが常に明確であるとは限りません。(gotoを使用して)宗教的に嫌うものを避けるためだけに、何か(機能を持つ)を強制しています。何か間違ったことをしていることの明確な兆候。
o0 '。

3
@Justin関数呼び出しにはオーバーヘッドがあります。gotoではない。考慮すべきこと。
Dan Bechard、

2

プロセッサは少なくとも1つのジャンプ命令を実装しており、多くのステートメントがそれらの実装または解釈でそれらを使用していると確信しています。

第3または第4世代の言語を使用することの良い点の1つは、これらの物理的な詳細が抽象化されていることです。漏れやすい抽象化法則に注意する必要がありますが、ツールも意図したとおりに使用する必要があります(申し訳ありません)。私がコードを書いていてgoto、それが良い考えのように思われたら、リファクタリングする時がきたでしょう。構造化言語の目的は、これらの「ジャンプ」を回避し、エンジニアリングに論理的なフローを作成することです。

の使用は避けるべきですbreakが、パフォーマンスの利点を見逃すことはできません。ただし、相互に必要なネストされたループがあるbreak場合は、リファクタリングする時間です。

誰かがgotoそれを使用することを提案できる場合は、リファクタリングよりも良いようですが、私は喜んで私の答えを取り下げます。

私がここの「自転車置き場」に急いで罪を犯していないことを願っています。クラーゲンが言うように、ダイクストラにとって十分なものは私にとって十分なものです。


1
撮影dynamic対象を、私は必要な値にまで取得するには複数の辞書が含まれていることのオブジェクトグラフを歩きます。dynamicまだ正確なオブジェクトの形状を期待するパラメータを持つメソッドを使用しても意味がありません。gotoを使用して複数のレイヤーを分割し、これらのオブジェクトのコレクションを順に見ていきます。[私はタイプを所有していないので、より良いアクセスを提供できません。そのため、リフレクションまたはダイナミックです]
Chris Marisic '20 / 08/20

-6

後藤は決して良くない。続けて、ブレーク(スイッチ/ケースを除く)、(複数回)リターン、スローも最低限に抑える必要があります。ネストループの途中から逃げたくない。ループ制御ステートメントには常にすべてのループ制御が必要です。インデントには情報があり、これらすべてのステートメントはその情報を破棄します。インデントをすべて削除することもできます。


10
ループの実行を維持する意味がない場合は、ループから抜け出す必要があります。そうしないと、理由もなく、長いループでより多くの処理時間を浪費することになります。
Skuld

12
@カーク、これは定量的というよりは意見のように聞こえますか?
ブライアンスコット
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.