web-dev-qa-db-ja.com

Switchステートメントに複数の場合

case value:を何度も記述せずに複数のcaseステートメントを調べてしまう方法はありますか?

私はこの作品を知っています:

switch (value)
{
   case 1:
   case 2:
   case 3:
      //do some stuff
      break;
   case 4:
   case 5:
   case 6:
      //do some different stuff
      break;
   default:
       //default stuff
      break;
}

しかし、私はこのようなことをしたいのですが。

switch (value)
{
   case 1,2,3:
      //Do Something
      break;
   case 4,5,6:
      //Do Something
      break;
   default:
      //Do the Default
      break;
}

この構文は私が別の言語から考えているのでしょうか、それとも何かが足りないのでしょうか。

517
theo

あなたが言及した2番目の方法のためのC++にもC#にも構文はありません。

最初の方法に問題はありません。ただし、範囲が非常に広い場合は、一連のif文を使用してください。

282
Brian R. Bondy

これはすでに答えられていると思います。しかし、私はあなたがまだやることによって構文的により良い方法で両方のオプションを混在させることができると思います:

switch (value)
{
case 1: case 2: case 3:          
    // Do Something
    break;
case 4: case 5: case 6: 
    // Do Something
    break;
default:
    // Do Something
    break;
}
640

この構文は、Visual Basicからのものです。 Select ... Caseステートメント

Dim number As Integer = 8
Select Case number
    Case 1 To 5
        Debug.WriteLine("Between 1 and 5, inclusive")
        ' The following is the only Case clause that evaluates to True.
    Case 6, 7, 8
        Debug.WriteLine("Between 6 and 8, inclusive")
    Case Is < 1
        Debug.WriteLine("Equal to 9 or 10")
    Case Else
        Debug.WriteLine("Not between 1 and 10, inclusive")
End Select

C#ではこの構文を使用できません。代わりに、最初の例の構文を使用する必要があります。

65
Neal

元の質問には少し遅れましたが、新しいバージョンを使用している人のためにこの回答を投稿しています( C#7 - Visual Studio 2017/.NET Framework 4.6.2 でデフォルトで使用可能) 、それが参考になるでしょう。

C#7では、範囲ベースの切り替えは switchステートメント で可能になり、OPの問題に役立ちます。

例:

int i = 5;

switch (i)
{
    case int n when (n >= 7):
        Console.WriteLine($"I am 7 or above: {n}");
        break;

    case int n when (n >= 4 && n <= 6 ):
        Console.WriteLine($"I am between 4 and 6: {n}");
        break;

    case int n when (n <= 3):
        Console.WriteLine($"I am 3 or less: {n}");
        break;
}

// Output: I am between 4 and 6: 5

注:

  • ()は、when条件では必要ありませんが、この例では比較を強調するために使用されています。
  • varintの代わりに使用することもできます。例えば、case var n when n >= 7:です。
47
Steve Gomez

あなたはあなたを与える改行を省略することができます。

case 1: case 2: case 3:
   break;

しかし、私はその悪いスタイルを考えます。

31
Allan Wind

.NET Framework 3.5には範囲があります。

Enumerable.Range from MSDN

他の人が言ったようにSWITCHステートメントは "=="演算子を使用するので、 "contains"とIFステートメントで使用できます。

ここに例があります:

int c = 2;
if(Enumerable.Range(0,10).Contains(c))
    DoThing();
else if(Enumerable.Range(11,20).Contains(c))
    DoAnotherThing();

しかし、私たちはもっと楽しくなることができると思います:あなたは戻り値を必要とせず、このアクションはパラメータをとらないので、あなたは簡単にアクションを使うことができます!

public static void MySwitchWithEnumerable(int switchcase, int startNumber, int endNumber, Action action)
{
    if(Enumerable.Range(startNumber, endNumber).Contains(switchcase))
        action();
}

この新しい方法での古い例:

MySwitchWithEnumerable(c, 0, 10, DoThing);
MySwitchWithEnumerable(c, 10, 20, DoAnotherThing);

値ではなくアクションを渡すので、括弧は省略する必要があります。これは非常に重要です。引数付きの関数が必要な場合は、Actionの型をAction<ParameterType>に変更するだけです。戻り値が必要な場合はFunc<ParameterType, ReturnType>を使用してください。

C#3.0では、caseパラメータが同じという事実をカプセル化する簡単な 部分的なアプリケーション はありませんが、ちょっとしたヘルパーメソッドを作成します(少し冗長です)。

public static void MySwitchWithEnumerable(int startNumber, int endNumber, Action action){ 
    MySwitchWithEnumerable(3, startNumber, endNumber, action); 
}

ここでは、新しい関数のインポートされた文が、古い命令よりも強力かつエレガントになっている例を示します。

18
Luca Molteni

@ジェニファーオーウェンズ:あなたは絶対に正しい下のコードが動作しません:

case 1 | 3 | 5:
//not working do something

これを行う唯一の方法は、次のとおりです。

case 1: case 2: case 3:
// do something
break;

あなたが探しているコードは、あなたが簡単に範囲を置くことができるビジュアルベーシック上で動作します。あなたのC#プロジェクトに。

注:ビジュアルベーシックで同等のスイッチを選択するのは大文字小文字を区別します。

8
none

もう1つの選択肢は、ルーチンを使用することです。ケース1〜3がすべて同じロジックを実行する場合は、そのロジックをルーチンでラップして、各ケースに対して呼び出します。私はこれが実際にcase文を取り除くわけではないことを知っています、しかしそれは良いスタイルを実装し、メンテナンスを最小限に保ちます.....

[編集]元の質問に合わせて代替の実装を追加しました... [/編集]

switch (x)
{
   case 1:
      DoSomething();
      break;
   case 2:
      DoSomething();
      break;
   case 3:
      DoSomething();
      break;
   ...
}

private void DoSomething()
{
   ...
}

Alt

switch (x)
{
   case 1:
   case 2:
   case 3:
      DoSomething();
      break;
   ...
}

private void DoSomething()
{
   ...
}
7
Dr8k

gccはシーケンシャル範囲をサポートするためにC言語への拡張を実装します。

switch (value)
{
   case 1...3:
      //Do Something
      break;
   case 4...6:
      //Do Something
      break;
   default:
      //Do the Default
      break;
}

編集する:質問のC#タグに気付いただけなので、おそらくgccの答えは役に立ちません。

5
DGentry

これが完全なC#7ソリューションです。

switch (value)
{
   case var s when new[] { 1,2,3 }.Contains(s):
      //Do Something
      break;
   case var s when new[] { 4,5,6 }.Contains(s):
      //Do Something
      break;
   default:
      //Do the Default
      break;
}

文字列でも動作します...

switch (mystring)
{
   case var s when new[] { "Alpha","Beta","Gamma" }.Contains(s):
      //Do Something
      break;
...
}
5
Carter Medlin

C#での switch のあまり知られていない面は operator = に依存しているということです。


string s = foo();

switch (s) {
  case "abc": /*...*/ break;
  case "def": /*...*/ break;
}

実は私もGOTOコマンドが好きではありません、しかしそれは公式のMS資料にあります、ここにすべて許可された構文があります。

Switchセクションのステートメントリストの終点が到達可能な場合は、コンパイル時エラーが発生します。これは「転倒しない」規則として知られています。例

switch (i) {
case 0:
   CaseZero();
   break;
case 1:
   CaseOne();
   break;
default:
   CaseOthers();
   break;
}

どのスイッチセクションにも到達可能なエンドポイントがないため有効です。 CやC++とは異なり、スイッチセクションの実行は次のスイッチセクションへの「フォールスルー」を許可されていません。

switch (i) {
case 0:
   CaseZero();
case 1:
   CaseZeroOrOne();
default:
   CaseAny();
}

コンパイル時エラーになります。 switchセクションの実行の後に別のswitchセクションの実行が続く場合は、明示的なgoto caseまたはgoto defaultステートメントを使用する必要があります。

switch (i) {
case 0:
   CaseZero();
   goto case 1;
case 1:
   CaseZeroOrOne();
   goto default;
default:
   CaseAny();
   break;
}

スイッチセクションでは複数のラベルを使用できます。例

switch (i) {
case 0:
   CaseZero();
   break;
case 1:
   CaseOne();
   break;
case 2:
default:
   CaseTwo();
   break;
}

私は、この特定のケースでは、GOTOを使用できると考えています。実際には、それがフォールスルーする唯一の方法です。

ソース: http://msdn.Microsoft.com/ja-jp/library/aa664749%28v=vs.71%29.aspx

3
Jiří Herník

C#で使用頻度の低い構文の1つを使用して、見栄えをよくしたり作業を改善する方法を見つけるために、多大な労力が費やされたようです。個人的には、switchステートメントを使用する価値はほとんどないと思います。私はあなたがどんなデータをテストしていて、あなたが欲しい最終結果を分析することを強く勧めます。

たとえば、既知の範囲内の値を素数かどうかをすばやくテストしたいとします。あなたのコードが無駄な計算をしないようにしたい、そしてあなたがオンラインで欲しい範囲の素数のリストを見つけることができます。大規模なswitchステートメントを使用して、各値を既知の素数と比較することができます。

あるいは素数の配列マップを作成して即座に結果を得ることもできます。

    bool[] Primes = new bool[] {
        false, false, true, true, false, true, false,    
        true, false, false, false, true, false, true,
        false,false,false,true,false,true,false};
    private void button1_Click(object sender, EventArgs e) {
        int Value = Convert.ToInt32(textBox1.Text);
        if ((Value >= 0) && (Value < Primes.Length)) {
            bool IsPrime = Primes[Value];
            textBox2.Text = IsPrime.ToString();
        }
    }

たぶんあなたは文字列の中の文字が16進数であるかどうか見たいと思うでしょう。醜くてやや大きいswitch文を使うことができます。

あるいは、正規表現を使用して文字をテストするか、IndexOf関数を使用して既知の16進数の文字列で文字を検索することもできます。

        private void textBox2_TextChanged(object sender, EventArgs e) {
        try {
            textBox1.Text = ("0123456789ABCDEFGabcdefg".IndexOf(textBox2.Text[0]) >= 0).ToString();
        } catch {
        }
    }

1から24の範囲の値に応じて、3つの異なるアクションのうちの1つを実行したいとしましょう。一連のIFステートメントを使用することをお勧めします。そしてそれがあまりにも複雑になった場合(または1から90の範囲の値に応じて5つの異なるアクションのように数値が大きくなった場合)、enumを使用してアクションを定義し、enumの配列マップを作成します。その後、その値を使って配列マップにインデックスを付け、必要なアクションの列挙を取得します。次に、少数のIFステートメントまたは非常に単純なswitchステートメントを使用して、結果のenum値を処理します。

また、ある範囲の値をアクションに変換する配列マップのいいところは、コードによって簡単に変更できることです。ハードコードでは実行時に動作を簡単に変更できませんが、配列マップを使用すると簡単です。

2
Darin

非常に大量の文字列(または他の種類の)Caseがすべて同じことをしている場合は、string.Containsプロパティと組み合わせた文字列Listの使用をお勧めします。

だからあなたがそのような大きなswitch文を持っているなら:

switch (stringValue)
{
    case "cat":
    case "dog":
    case "string3":
    ...
    case "+1000 more string": //Too many string to write a case for all!
        //Do something;
    case "a lonely case"
        //Do something else;
    .
    .
    .
}

これを次のようなif文に置き換えることができます。

//Define all the similar "case" string in a List
List<string> listString = new List<string>(){ "cat", "dog", "string3", "+1000 more string"};
//Use string.Contains to find what you are looking for
if (listString.Contains(stringValue))
{
    //Do something;
}
else
{
    //Then go back to a switch statement inside the else for the remaining cases if you really need to
}

これは、任意の数の文字列の場合に適しています。

1
Maxter

会話に追加するだけで、.NET 4.6.2を使用して、次のこともできました。コードをテストしましたが、うまくいきました。

以下のように、複数の「OR」ステートメントを実行することもできます。

            switch (value)
            {
                case string a when a.Contains("text1"):
                    // Do Something
                    break;
                case string b when b.Contains("text3") || b.Contains("text4") || b.Contains("text5"):
                    // Do Something else
                    break;
                default:
                    // Or do this by default
                    break;
            }

配列の値と一致するかどうかも確認できます。

            string[] statuses = { "text3", "text4", "text5"};

            switch (value)
            {
                case string a when a.Contains("text1"):
                    // Do Something
                    break;
                case string b when statuses.Contains(value):                        
                    // Do Something else
                    break;
                default:
                    // Or do this by default
                    break;
            }
0
JeffS