题
有没有办法在不说明的情况下通过多个案例陈述 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;
}
这是我从不同的语言中想到的语法,还是我遗漏了一些东西?
解决方案
对于你提到的第二种方法,C++ 和 C# 中都没有语法。
你的第一种方法没有问题。但是,如果范围非常大,则只需使用一系列 if 语句即可。
其他提示
我想这已经得到答案了。但是,我认为您仍然可以通过执行以下操作以语法上更好的方式混合这两个选项:
switch (value)
{
case 1: case 2: case 3:
// Do Something
break;
case 4: case 5: case 6:
// Do Something
break;
default:
// Do Something
break;
}
该语法来自 Visual Basic 选择...案例陈述:
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# 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
条件,但在此示例中用于突出显示比较。 var
也可以用来代替int
. 。例如:case var n when n >= 7:
.
您可以省略换行符,它会为您提供:
case 1: case 2: case 3:
break;
但我认为这种风格很糟糕。
.NET Framework 3.5 有范围:
您可以将它与“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 参数是相同的事实,但您创建了一个小辅助方法(有点冗长,tho)。
public static void MySwitchWithEnumerable(int startNumber, int endNumber, Action action){
MySwitchWithEnumerable(3, startNumber, endNumber, action);
}
这是一个示例,说明新的函数式导入语句如何比旧的命令式语句更强大、更优雅。
@詹妮弗·欧文斯:你是绝对正确的,下面的代码将不起作用:
case 1 | 3 | 5:
//not working do something
执行此操作的唯一方法是:
case 1: case 2: case 3:
// do something
break;
您正在寻找的代码适用于 Visual Basic,您可以轻松地在其中放置范围...在没有 switch 选项或 if else 块方便的情况下,我建议在非常极端的情况下,使用 Visual Basic 制作 .dll 并导入回您的 C# 项目。
笔记:Visual Basic 中的 switch 相当于 select case。
另一种选择是使用例程。如果情况 1-3 都执行相同的逻辑,则将该逻辑包装在例程中并为每个情况调用它。我知道这实际上并没有摆脱 case 语句,但它确实实现了良好的风格并将维护降至最低限度......
[编辑]添加了替代实现以匹配原始问题...[/编辑]
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()
{
...
}
这是完整的 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;
...
}
一个鲜为人知的方面 转变 在 C# 中,它依赖于 运算符= 因为它可以被覆盖,所以你可以有这样的东西:
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 的答案可能没有帮助。
其实我也不喜欢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/en-us/library/aa664749%28v=vs.71%29.aspx
似乎已经投入了大量的工作来寻找方法,让 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 语句。
或者,您可以使用正则表达式来测试字符,或使用 IndexOf 函数在已知的十六进制字母字符串中搜索字符:
private void textBox2_TextChanged(object sender, EventArgs e) {
try {
textBox1.Text = ("0123456789ABCDEFGabcdefg".IndexOf(textBox2.Text[0]) >= 0).ToString();
} catch {
}
}
假设您想要根据 1 到 24 范围内的值执行 3 种不同操作之一。我建议使用一组 IF 语句。如果这变得太复杂(或者数字更大,例如 5 个不同的操作,具体取决于 1 到 90 范围内的值),则使用枚举来定义操作并创建枚举的数组映射。然后该值将用于索引数组映射并获取所需操作的枚举。然后使用一小组 IF 语句或非常简单的 switch 语句来处理生成的枚举值。
此外,将一系列值转换为操作的数组映射的好处是可以通过代码轻松更改它。使用硬连线代码,您无法轻松地更改运行时的行为,但使用数组映射则很容易。
如果您有大量字符串(或任何其他类型)的情况都在做同样的事情,我建议将字符串列表与 string.Contains 属性结合使用。
因此,如果你有一个像这样的大 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
}
这对于任何数量的字符串情况都能很好地扩展。
为此,您可以使用 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();
}