是否有一种方法可以通过多个case语句而不声明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;
}

这是我从另一种语言中想到的语法,还是我遗漏了什么?


你提到的第二个方法在c++和c#中都没有语法。

你的第一个方法没有问题。然而,如果你有很大的范围,只需使用一系列的If语句。


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


c#中switch的一个不太为人所知的方面是它依赖于操作符=,因为它可以被覆盖,所以你可以有这样的东西:


string s = foo();

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

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

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

编辑:刚刚注意到这个问题上有c#标签,所以gcc的答案可能没有帮助。


你可以省略换行符,它会给你:

case 1: case 2: case 3:
   break;

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


另一种选择是使用例行程序。如果案例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()
{
   ...
}

.NET Framework 3.5有如下的范围:

可列举的。范围从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中,没有简单的局部应用程序来封装case参数相同的事实,但您可以创建一个小的辅助方法(虽然有点啰嗦)。

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

这里有一个例子,说明新的函数导入语句如何比旧的命令式语句更强大和优雅。


我想这个问题已经有答案了。然而,我认为你仍然可以通过以下方式在语法上更好地混合这两个选项:

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

为此,您将使用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();
    }

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

如果可以到达开关段的语句列表的结束点,则会发生编译时错误。这就是所谓的“不失败”规则。这个例子

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,这实际上是唯一失败的方法。


为了让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();
        }
    }

也许你想看看字符串中的一个字符是否是十六进制的。您可以使用一个ungly和有点大的switch语句。

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

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

Let us say you want to do one of 3 different actions depending on a value that will be the range of 1 to 24. I would suggest using a set of IF statements. And if that became too complex (Or the numbers were larger such as 5 different actions depending on a value in the range of 1 to 90) then use an enum to define the actions and create an array map of the enums. The value would then be used to index into the array map and get the enum of the action you want. Then use either a small set of IF statements or a very simple switch statement to process the resulting enum value.

此外,将一系列值转换为操作的数组映射的好处是可以通过代码轻松更改它。使用硬连线代码,你不能轻易地在运行时改变行为,但使用数组映射则很容易。


下面的代码将无法工作:

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

做到这一点的唯一方法是:

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

您正在寻找的代码在Visual Basic中工作,您可以轻松地将范围…在switch语句的none选项中,或者如果else blocks方便,我建议,在非常极端的情况下,用Visual Basic生成.dll,然后导入回c#项目中。

注意:在Visual Basic中等效的开关是“选择大小写”。


c# 7的原始答案

在c# 7中(默认在Visual Studio 2017中可用)。NET Framework 4.6.2),基于范围的切换现在可以通过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条件中不是必需的,但在本例中用于突出显示比较。 Var也可以用来代替int。例如:case var n when n >= 7:。


c# 9的更新示例

switch(myValue)
{
    case <= 0:
        Console.WriteLine("Less than or equal to 0");
        break;
    case > 0 and <= 10:
        Console.WriteLine("More than 0 but less than or equal to 10");
        break;
    default:
        Console.WriteLine("More than 10");
        break;
}

or

var message = myValue switch
{
    <= 0 => "Less than or equal to 0",
    > 0 and <= 10 => "More than 0 but less than or equal to 10",
    _ => "More than 10"
};
Console.WriteLine(message);

如果你有非常大量的字符串(或任何其他类型)的情况下都做同样的事情,我建议使用字符串列表结合字符串。包含属性。

如果你有一个大的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
}

这适用于任意数量的字符串情况。


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

只是为了增加对话,使用. 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;
            }

在c# 7中,我们现在有了模式匹配,所以你可以这样做:

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

我认为这个在c# 7或更高版本中更好。

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

你也可以在c#的开关情况下检查范围:开关情况:我可以使用一个范围而不是一个数字

OR

 int i = 3;

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

在c#中切换多个情况

或者如果你想了解基础知识 c#开关箱


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

在c# 9的关系模式深度教程中

c# 9.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;
            }

在c# 8.0中,您可以使用新的开关表达式语法,这是您的理想情况。

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

更漂亮的处理方式

if ([4, 5, 6, 7].indexOf(value) > -1)
    //Do something

您可以为具有相同结果的多个值执行此操作


我们还可以使用这种方法在switch语句中实现Multiple case…使用这种方法,您可以使用任意多的条件。

    int i = 209;
    int a = 0;
    switch (a = (i>=1 && i<=100) ? 1 : a){    
    case 1:
        System.out.println ("The Number is Between 1 to 100 ==> " + i);
        break;
    default:
        switch (a = (i>100 && i<=200) ? 2 : a) {
            case 2:
                System.out.println("This Number is Between 101 to 200 ==> " + i);
                break;
        
            default:
                switch (a = (i>200 && i<=300) ? 3 : a) {
                    case 3:
                        System.out.println("This Number is Between 201 to 300 ==> " + i);
                        break;
                
                    default:
                        // You can make as many conditions as you want;
                        break;
                }
        }
        
    }

使用新版本的c#我已经这样做了

public string GetValue(string name)
            {
                return name switch
                {
                    var x when name is "test1" || name is "test2" => "finch",
                    "test2" => somevalue,
                    _ => name
                };
            }