C# 当对子句求值时,switch语句的顺序是什么?
考虑以下示例:C# 当对子句求值时,switch语句的顺序是什么?,c#,switch-statement,pattern-matching,C#,Switch Statement,Pattern Matching,考虑以下示例: public static double ComputeArea_Version3(object shape) { switch (shape) { case Square s when s.Side == 0: case Circle c when c.Radius == 0: return 0; case Square s: return s.Side * s.S
public static double ComputeArea_Version3(object shape)
{
switch (shape)
{
case Square s when s.Side == 0:
case Circle c when c.Radius == 0:
return 0;
case Square s:
return s.Side * s.Side;
case Circle c:
return c.Radius * c.Radius * Math.PI;
default:
throw new ArgumentException(
message: "shape is not a recognized shape",
paramName: nameof(shape));
}
}
当s.Side==0时,when
子句case Square s:
是否保证在更通用的case Square s:
之前执行?是什么决定了开关中的顺序和位置?如果我写的是:
public static double ComputeArea_Version3(object shape)
{
switch (shape)
{
case Square s:
return s.Side * s.Side;
case Circle c:
return c.Radius * c.Radius * Math.PI;
case Square s when s.Side == 0:
case Circle c when c.Radius == 0:
return 0;
default:
throw new ArgumentException(
message: "shape is not a recognized shape",
paramName: nameof(shape));
}
}
当
条款永远不会被评估时,条款会不会被评估?案例条款会按照代码指示的顺序被评估
一个开关不过是一系列的if-then-if-then-else等等,在一个简洁易读的问题上
因此,如果您放置一个break、return、throw或goto语句,那么它会在第一个true条件下中断解析,否则它们也会被连续检查
例如,您可以编写:
case 0:
case 1:
DoSomething();
break;
但你不能写:
case 0:
DoSomething();
// break or return or throw or goto needed here
case 1:
DoAnotherSomething();
break;
您可以使用一些示例逐行调试以检查这一点
您的第二个示例无法编译,因为必须将条件从特定设置为一般设置
例如:
object instance = new Form();
switch ( instance )
{
case Form f when f.Text == "Test":
return;
case Form f:
return;
case Label l:
return;
}
生成的IL代码:
// object obj = new Form();
IL_0001: newobj instance void [System.Windows.Forms]System.Windows.Forms.Form::.ctor()
IL_0006: stloc.0
// object obj2 = obj;
IL_0007: ldloc.0
IL_0008: stloc.s 7
// object obj3 = obj2;
IL_000a: ldloc.s 7
IL_000c: stloc.1
// if (obj3 == null)
IL_000d: ldloc.1
// (no C# code)
IL_000e: brtrue.s IL_0012
// }
IL_0010: br.s IL_002c
// if ((form = (obj3 as Form)) == null)
IL_0012: ldloc.1
IL_0013: isinst [System.Windows.Forms]System.Windows.Forms.Form
// (no C# code)
IL_0018: dup
IL_0019: stloc.2
IL_001a: brfalse.s IL_0020
IL_001c: br.s IL_002e
IL_001e: br.s IL_0048
// if ((label = (obj3 as Label)) != null)
IL_0020: ldloc.1
IL_0021: isinst [System.Windows.Forms]System.Windows.Forms.Label
// (no C# code)
IL_0026: dup
IL_0027: stloc.3
IL_0028: brfalse.s IL_002c
IL_002a: br.s IL_004f
IL_002c: br.s IL_0056
// Form form2 = form;
IL_002e: ldloc.2
IL_002f: stloc.s 4
// if (!(form2.Text == "Test"))
IL_0031: ldloc.s 4
IL_0033: callvirt instance string [System.Windows.Forms]System.Windows.Forms.Control::get_Text()
IL_0038: ldstr "Test"
IL_003d: call bool [mscorlib]System.String::op_Equality(string, string)
// (no C# code)
IL_0042: brtrue.s IL_0046
IL_0044: br.s IL_001e
IL_0046: br.s IL_0056
// Form form3 = form;
IL_0048: ldloc.2
IL_0049: stloc.s 5
// (no C# code)
IL_004b: br.s IL_004d
IL_004d: br.s IL_0056
// Label label2 = label;
IL_004f: ldloc.3
IL_0050: stloc.s 6
// (no C# code)
IL_0052: br.s IL_0054
IL_0054: br.s IL_0056
IL_0056: ret
如您所见,此代码是一系列测试和分支
确认订单与代码中所写的一致:
开关表达式按文本顺序计算。执行
传输到与交换机匹配的第一个交换机标签
表情
虽然您的第二个示例不会像@OlivierRogier在中解释的那样编译是正确的,但顺序仍然很重要。考虑这个代码片段:
object o = 42;
switch (o)
{
case int i when i > 10:
Console.WriteLine("Greater 10");
break;
case int j when j > 20:
Console.WriteLine("Greater 20");
break;
}
这将打印大于10的。但是如果你把这两个案例切换到
switch (o)
{
case int j when j > 20:
Console.WriteLine("Greater 20");
break;
case int i when i > 10:
Console.WriteLine("Greater 10");
break;
}
它仍然会编译,但会打印Greater 20
您已经在调用return
行,因此它不会到达后续的case语句。我想他是在问,当不满足case时,它们是否会按顺序进行。他想知道这些条件是否按顺序评估。答案是肯定的,这些案例是按照它们提供的顺序考虑的。@DetectivePikachu你是对的。我不认为你的答案大体上是正确的。据我所知,C#能够为常量值switch
语句生成哈希表,这将使排序静音。它只会为>7种情况生成字典。尽管我不知道编译器会产生一个错误,但排序仍然是无意义的。在第二个示例中,开关案例已经由前一个案例处理。
。好的观点。解释这个编译错误何时出现很重要:“开关案例已经被前一个案例处理过。”有趣的事实是,当
时,你可以重复相同的案例,编译器不会在意,因为它只会检查当
时是否有一个案例
已经覆盖了案例,但是当
零件时,不会真正检查。