switch语句中的多个案例

时间:2008-09-16 01:34:41

标签: c# switch-statement

有没有办法在不重复陈述case value:的情况下通过多个案例陈述?

我知道这有效:

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

这种语法我是用其他语言思考的,还是我错过了什么?

22 个答案:

答案 0 :(得分:641)

我想这已经回答了。但是,我认为您仍然可以通过以下方式在语法上更好地混合两个选项:

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

答案 1 :(得分:285)

对于您提到的第二种方法,C ++和C#都没有语法。

你的第一种方法没有错。但是,如果你有很大的范围,只需使用一系列if语句。

答案 2 :(得分:67)

此语法来自Visual Basic Select...Case Statement

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#中使用此语法。相反,您必须使用第一个示例中的语法。

答案 3 :(得分:47)

原始问题有点迟了,但我发布了这个答案,希望有人使用更新的版本( C#7 - 默认情况下在Visual Studio 2017 / .NET Framework 4.6中可用。 2 ),会觉得有帮助。

在C#7中,现在可以使用switch statement进行基于范围的切换,并有助于解决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,但在此示例中使用括号来突出显示比较。
  • var也可用于代替int。例如:case var n when n >= 7:

答案 4 :(得分:31)

你可以省略给你的换行符:

case 1: case 2: case 3:
   break;

但我认为那种不好的风格。

答案 5 :(得分:18)

.NET Framework 3.5有范围:

Enumerable.Range from MSDN

你可以将它与“contains”和IF语句一起使用,因为有人说SWITCH语句使用“==”运算符。

这是一个例子:

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中,没有简单的Partial Application来封装case参数相同的事实,但你创建了一个小帮助方法(有点冗长,等等)。

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

这里有一个新功能导入语句如何比旧命令更强大和优雅的例子。

答案 6 :(得分:8)

@ Jennifer Owens:你绝对正确,下面的代码不起作用:

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

唯一的方法是:

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

你正在寻找的代码适用于visual basic,你可以很容易地放置范围...在没有选项的开关或if else块方便,我建议,在非常极端的点,使用visual basic制作.dll并导入回你的c#项目。

注意:在visual basic中切换等效项是选择大小写。

答案 7 :(得分:7)

另一种选择是使用例程。如果案例1-3都执行相同的逻辑,则将该逻辑包装在例程中并为每个案例调用它。我知道这实际上并没有摆脱案例陈述,但它确实实现了良好的风格并将维护保持在最低限度.....

[编辑]添加了替代实施以匹配原始问题... [/编辑]

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

private void DoSomething()
{
   ...
}

<强>替代

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

private void DoSomething()
{
   ...
}

答案 8 :(得分:6)

这是完整的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;
...
}

答案 9 :(得分:6)

C#9 带来了关系模式匹配。这使我们能够:

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

In deep tutorial of Relational Patter in C#9

Pattern-matching changes for C# 9.0

<块引用>

关系模式允许程序员表达一个输入 与常量相比,值必须满足关系约束 价值

答案 10 :(得分:5)

gcc实现了C语言的扩展,以支持顺序范围:

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

编辑:刚刚注意到问题上的C#标签,所以大概是gcc的答案没有帮助。

答案 11 :(得分:5)

C#中 switch 的一个鲜为人知的方面是它依赖于 operator = ,因为它可以被覆盖,你可以这样:


string s = foo();

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

答案 12 :(得分:3)

实际上我也不喜欢GOTO命令,但它在官方MS材料中,这里都是允许的语法。

如果可以访问switch部分的语句列表的结束点,则会发生编译时错误。这被称为&#34; no fall through&#34;规则。例子

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

有效,因为没有切换部分具有可到达的终点。与C和C ++不同,切换部分的执行不允许&#34;通过&#34;到下一个开关部分,以及示例

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

导致编译时错误。当执行交换机部分后执行另一个交换机部分时,必须使用显式的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/en-us/library/aa664749%28v=vs.71%29.aspx

答案 13 :(得分:2)

似乎已经投入了大量的工作来寻找使C#最少使用的语法之一以某种方式看起来更好或更好的方法。就个人而言,我发现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();
        }
    }

也许您想查看字符串中的字符是否为十六进制。你可以使用一个无意义且有点大的switch语句。

或者您可以使用正则表达式来测试char或使用IndexOf函数在已知十六进制字母的字符串中搜索char:

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

让我们假设您想要执行3种不同操作之一,具体取决于1到24范围内的值。我建议使用一组IF语句。如果它变得太复杂(或者数字更大,例如5个不同的动作,取决于1到90范围内的值),那么使用枚举来定义动作并创建枚举的数组映射。然后,该值将用于索引数组映射并获取所需操作的枚举。然后使用一小组IF语句或一个非常简单的switch语句来处理生成的枚举值。

此外,将一系列值转换为动作的数组映射的优点在于它可以通过代码轻松更改。使用硬连线代码,您无法在运行时轻松更改行为,但使用阵列映射很容易。

答案 14 :(得分:2)

我认为这在C#7或更高版本中会更好。

switch (value)
{
    case var s when new[] { 1,2 }.Contains(s):
    // Do something
     break;

    default:
    // Do the default
    break;
 }

您还可以在C#开关情况下检查范围:Switch case: can I use a range instead of a one number 或者,如果您想了解 C# switch case

答案 15 :(得分:2)

在 C# 8.0 中,您可以使用新的 switch expression 语法,它非常适合您的情况。

var someOutput = value switch
{
    >= 1 and <= 3 => <Do some stuff>,
    >= 4 and <= 6 => <Do some different stuff>,
    _ => <Default stuff>
};

答案 16 :(得分:1)

如果你有大量的字符串(或任何其他类型)Case都做同样的事情,我建议使用字符串List和string.Contains属性。

所以如果你有一个像这样的大转换声明:

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
}

这适用于任何数量的字符串大小。

答案 17 :(得分:1)

在C#7中,我们现在有了Pattern Matching,因此您可以执行以下操作:

switch (age)
{
  case 50:
    ageBlock = "the big five-oh";
    break;
  case var testAge when (new List<int>()
      { 80, 81, 82, 83, 84, 85, 86, 87, 88, 89 }).Contains(testAge):
    ageBlock = "octogenarian";
    break;
  case var testAge when ((testAge >= 90) & (testAge <= 99)):
    ageBlock = "nonagenarian";
    break;
  case var testAge when (testAge >= 100):
    ageBlock = "centenarian";
    break;
  default:
    ageBlock = "just old";
    break;
}

答案 18 :(得分:0)

只需添加到使用.NET 4.6.2的对话中,我还可以执行以下操作。 我测试了代码,它确实对我有用。

您还可以执行多个“或”语句,如下所示:

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

答案 19 :(得分:0)

你也可以有完全不同的条件

            bool isTrue = true;

            switch (isTrue)
            {
                case bool ifTrue when (ex.Message.Contains("not found")):
                case bool ifTrue when (thing.number = 123):
                case bool ifTrue when (thing.othernumber != 456):
                    response.respCode = 5010;
                    break;
                case bool ifTrue when (otherthing.text = "something else"):
                    response.respCode = 5020;
                    break;
                default:
                    response.respCode = 5000;
                    break;
            }

答案 20 :(得分:0)

对我来说最好的方法是用动作字典替换你的开关:

Using Action dictionaries instead of switch statements

该操作是通过键调用的,因此不需要条件。您也可以为不同的键填充相同的操作。

答案 21 :(得分:-4)

为此,您将使用goto语句。如:

    switch(value){
    case 1:
        goto case 3;
    case 2:
        goto case 3;
    case 3:
        DoCase123();
    //This would work too, but I'm not sure if it's slower
    case 4:
        goto case 5;
    case 5:
        goto case 6;
    case 6:
        goto case 7;
    case 7:
        DoCase4567();
    }