编译以下代码。
public static int Main(string[] args)
{
switch (args[0])
{
case "x": return 1;
case "y": return 2;
case "z": return 3;
}
return 0;
}
现在使用 Reflector 或 ILDASM 检查 C# 编译器生成的 IL。继续添加case语句,反编译观察结果。
- 如果 case 语句的数量很少,则编译器会发出顺序相等比较。
- 如果 case 语句的数量很大,则编译器会发出
Dictionary 查找。
我使用的是 C# 3.0 编译器,我观察到策略在 7 个 case 语句处发生了变化。我怀疑你会看到与 C# 4.0 和其他类似的东西。
更新:
我应该指出,您将在 IL 输出中看到对 Dictionary.Add 的调用,它正在构建字典以供以后使用。不要被愚弄以为每次都会发生这种情况。编译器实际上正在生成一个单独的静态类并对其进行内联静态初始化。请特别注意 L_0026 处的说明。如果该类已经初始化,那么分支将跳过 Add 调用。
L_0021: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string, int32> <PrivateImplementationDetails>{816396DD-F271-4C12-83D0-CC9C9CD67AD6}::$$method0x6000001-1
L_0026: brtrue.s L_0089
L_0028: ldc.i4.7
L_0029: newobj instance void [mscorlib]System.Collections.Generic.Dictionary`2<string, int32>::.ctor(int32)
L_002e: dup
L_002f: ldstr "x"
L_0034: ldc.i4.0
L_0035: call instance void [mscorlib]System.Collections.Generic.Dictionary`2<string, int32>::Add(!0, !1)
L_003a: dup
L_003b: ldstr "y"
L_0040: ldc.i4.1
L_0041: call instance void [mscorlib]System.Collections.Generic.Dictionary`2<string, int32>::Add(!0, !1)
L_0046: dup
L_0047: ldstr "z"
L_004c: ldc.i4.2
L_004d: call instance void [mscorlib]System.Collections.Generic.Dictionary`2<string, int32>::Add(!0, !1)
另外,请注意字典实际上包含从原始字符串到整数的映射。这个整数用于在 IL 中制定一个单独的开关。
L_0089: volatile.
L_008b: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string, int32> <PrivateImplementationDetails>{816396DD-F271-4C12-83D0-CC9C9CD67AD6}::$$method0x6000001-1
L_0090: ldloc.2
L_0091: ldloca.s CS$0$0002
L_0093: call instance bool [mscorlib]System.Collections.Generic.Dictionary`2<string, int32>::TryGetValue(!0, !1&)
L_0098: brfalse.s L_00da
L_009a: ldloc.3
L_009b: switch (L_00be, L_00c2, L_00c6, L_00ca, L_00ce, L_00d2, L_00d6)
L_00bc: br.s L_00da
L_00be: ldc.i4.1
L_00bf: stloc.1
L_00c0: br.s L_00de
L_00c2: ldc.i4.2
L_00c3: stloc.1
L_00c4: br.s L_00de
L_00c6: ldc.i4.3
更新 2:
对于它的价值,VB.NET 似乎没有对其Select 构造进行同样的优化。