web-dev-qa-db-ja.com

switchステートメントを含むwhileループから抜け出す

Switchステートメントを含むループから抜け出す方法を見つけるのに問題があります。ブレークは、ループではなくスイッチから発生します。

これにはおそらくもっとエレガントな解決策があります。 trueから始まりfalseに設定されてループを終了するフラグを実装しました。より良いソリューションを提供できますか?

背景:このコードはバーコードワークフローシステムで使用されます。バーコードスキャナーが組み込まれたPocketPCがあります。このコードは、これらの機能の1つで使用されます。ルーチン全体でさまざまなデータを入力するようユーザーに求めます。この部分により、PocketPCターミナルにその情報を表示する一部のインベントリレコード(ページングされた結果)をスクロールし、「D」を入力して完了、「Q」を入力して終了できます。

改善が必要な現在のC#の例を次に示します。

do
{
    switch (MLTWatcherTCPIP.Get().ToUpper())
    {
        case "": //scroll/display next inventory location
            MLTWatcherTCPIP.TerminalPrompt.ScrollBodyTextDown();
            break;
        case "P": //scroll/display previous inventory location
            MLTWatcherTCPIP.TerminalPrompt.ScrollBodyTextDown();
            break;
        case "D": //DONE (exit out of this Do Loop)
            // break; // this breaks out of the switch, not the loop
            // return; // this exists entire method; not what I'm after
            keepOnLooping = false;
            break;
        case "Q": //QUIT (exit out to main menu)
            return;
        default:
            break;
    }
} while (keepOnLooping);

VB.NETでこれを行うコードの例を次に示します

Do
    Select Case MLTWatcherTCPIP.Get().ToUpper
        Case "" ''#scroll/display next inventory location
            MLTWatcherTCPIP.TerminalPrompt.ScrollBodyTextDown()
        Case "P" ''#scroll/display previous inventory location
            MLTWatcherTCPIP.TerminalPrompt.ScrollBodyTextUp()
        Case "D" ''#DONE (exit out of this Do Loop)
            Exit Do
        Case "Q" ''#QUIT (exit out to main menu)
            Return
    End Select
Loop

おかげで、

50
joshblair

私はこのフォームが非常に読みやすいと感じています:

bool done = false;
while (!done) 
{ 
    switch (MLTWatcherTCPIP.Get().ToUpper()) 
    { 
        case "": //scroll/display next inventory location 
            MLTWatcherTCPIP.TerminalPrompt.ScrollBodyTextDown(); 
            break; 
        case "P": //scroll/display previous inventory location 
            MLTWatcherTCPIP.TerminalPrompt.ScrollBodyTextDown(); 
            break; 
        case "D": //DONE (exit out of this Do Loop) 
            done = true;
            break; 
        case "Q": //QUIT (exit out to main menu) 
            return; 
        default: 
            break; 
    } 
}
39

私はそれを避けようとしますが、あなたは使うことができます...

後藤

ただし、熊手を備えた怒っているMobは、そうすることを選択した場合、職業上の危険になります。

44
Kevin Montrose

ここでの1つのオプションは、このループをメソッドにリファクタリング(「抽出メソッド」)し、returnを使用することです。

30
Marc Gravell

私が知っている唯一の他の方法は、恐ろしいgotoです。 MSDNもこれを言っています。

ただし、この場合に使用する理由はわかりません。実装した方法は正常に機能し、gotoよりも保守が容易です。私はあなたが持っているものを保持します。

12
McAden

マルチレベルのブレークにはgotoステートメントを使用する必要があります。 C#で唯一の「クリーン」な方法のようです。フラグを使用することも有用ですが、ループに他の実行条件がある場合、追加のコードが必要です。

http://msdn.Microsoft.com/en-us/library/aa664756(VS.71).aspx

興味深いことに、他の非c言語にはbreak levels;(Javaは継続として偽装されたgotoを使用するため、同様に役に立たない..:P)

10
Tor Valamo

ループを続けるためにブール値を返すメソッドにスイッチをラップしませんか?コードを読みやすくするという副次的な利点があります。誰かがgotoステートメントを必要としないという論文を書いた理由があります;)

do
{
    bool keepOnLooping = TryToKeepLooping();
} while (keepOnLooping);

private bool TryToKeepLooping()
{
    switch (MLTWatcherTCPIP.Get().ToUpper())
    {
        case "": //scroll/display next inventory location
            MLTWatcherTCPIP.TerminalPrompt.ScrollBodyTextDown();
            break;
        case "P": //scroll/display previous inventory location
            MLTWatcherTCPIP.TerminalPrompt.ScrollBodyTextDown();
            break;
        case "D": //DONE (exit out of this Do Loop)
            // break; // this breaks out of the switch, not the loop
            // return; // this exists entire method; not what I'm after
            return false;
        case "Q": //QUIT (exit out to main menu)
            return true;
        default:
            break;
    }

    return true;
}
8
Jeffrey Cameron

外側のループから簡単に抜け出すことはできませんが、continueできます。

ロジックを逆にすると、これが得られます。ループを終了するためのswitchステートメントの直後にbreakがあることに注意してください。

私の意見では、これは非常に読みやすいコードではなく、フラグがまだ最適だと思います。

   do
         {
            switch (Console.ReadKey().KeyChar.ToString())
            {
                case "U":
                    Console.WriteLine("Scrolling up");
                    continue;

                case "J":
                    Console.WriteLine("Scrolling down");
                    continue;

                case "D": //DONE (exit out of this Do Loop)
                    break;

                case "Q": //QUIT (exit out to main menu)
                    return;

                default:
                    Console.WriteLine("Continuing");
                    continue;
            }

            break;

        } while (true);

        Console.WriteLine("Exited");
4
Simon_Weaver

フラグはこれを行う標準的な方法です。私が知っている他の唯一の方法は、gotoを使用することです。

4
John Knoeller

switchステートメントをif/elseステートメントに置き換えることができます。 gotoは不要で、breakステートメントはループを抜けます:

do
{
  String c = MLTWatcherTCPIP.Get().ToUpper();

  if (c = "")
    MLTWatcherTCPIP.TerminalPrompt.ScrollBodyTextDown();
  else if (c = "P")
    MLTWatcherTCPIP.TerminalPrompt.ScrollBodyTextUp();
  else if (c = "D")
     break;
  else if (c = "Q")
    return;
  else
  {
    // Handle bad input here.
  }
} while (keepLooping)
2

IMO、これはwhileループから抜け出す完全に素晴らしい方法のようです。それは副作用なしであなたが期待することをします。することを考えることができた

if(!keepOnLooping)
  break;

しかし、それは実際に実行の点で違いはありません。

1
Fry

関数にラップし、returnステートメントを使用して終了します。どのようにそのことについて?

1
Hamish Grubijan

次のように書きます:

case "Exit/Break" :
                  //Task to do
                    if(true)
                      break;

このブレークは、どのケースにも関連付けられません。 whileループに属します。

1

Switchステートメントをfor/foreachループに変更できます。条件が満たされたら、「keepOnLooping」をfalseに設定し、breakを使用してループから抜けます。残りは自分で処理する必要があります。

0
Chuck Conway

別の(それほど優れていない)代替方法は、caseを一意に処理し、ifで「ループから抜け出す」必要があり、switchブロックから移動することです。スイッチケースが非常に長い場合、それほどエレガントではありません。

do
{
    var expression = MLTWatcherTCPIP.Get().ToUpper();
    if (expression = "D") //DONE (exit out of this Do Loop)
    {   
        statement;
        break;
    }

    switch (expression)
    {
        case "": //scroll/display next inventory location
            MLTWatcherTCPIP.TerminalPrompt.ScrollBodyTextDown();
            break;
        case "P": //scroll/display previous inventory location
            MLTWatcherTCPIP.TerminalPrompt.ScrollBodyTextDown();
            break;
        case "Q": //QUIT (exit out to main menu)
            return;
        default:
            break;
    }
} while (true); //or whatever your condition is

また、case自体をwhileループの条件の一部にすることもできます。ループから抜け出すだけでよく、式自体の計算は簡単です(変数の読み取りなど)。

do
{
    switch (expression)
    {
        case "": //scroll/display next inventory location
            MLTWatcherTCPIP.TerminalPrompt.ScrollBodyTextDown();
            break;
        case "P": //scroll/display previous inventory location
            MLTWatcherTCPIP.TerminalPrompt.ScrollBodyTextDown();
            break;
        case "Q": //QUIT (exit out to main menu)
            return;
        default:
            break;
    }
} while (condition && expression != "D");

また、何らかの理由ですべてをリファクタリングして新しいメソッド(これに対する最もエレガントなソリューション)が受け入れられない場合、匿名デリゲートを使用して既存のメソッド内で同じことを行うこともできます。

0
nawfal