Kompilieren Sie den folgenden Code.
public static int Main(string[] args)
{
switch (args[0])
{
case "x": return 1;
case "y": return 2;
case "z": return 3;
}
return 0;
}
Verwenden Sie nun Reflektor o ILDASM um die vom C#-Compiler erzeugte AWL zu untersuchen. Fügen Sie weitere Case-Anweisungen hinzu, dekompilieren Sie und beobachten Sie das Ergebnis.
- Wenn die Anzahl der Case-Anweisungen gering ist, führt der Compiler einen sequentiellen Gleichheitsvergleich durch.
- Wenn die Anzahl der Case-Anweisungen groß ist, gibt der Compiler eine
Dictionary
Nachschlagen.
Ich habe den C# 3.0 Compiler verwendet und festgestellt, dass sich die Strategie bei 7 Case-Anweisungen ändert. Ich vermute, Sie werden etwas ähnliches mit C# 4.0 und anderen sehen.
Aktualisierung:
Ich möchte darauf hinweisen, dass Sie Aufrufe zu Dictionary.Add
in der AWL-Ausgabe, wo sie das Wörterbuch für die spätere Verwendung aufbaut. Lassen Sie sich nicht einreden, dass dies jedes Mal geschieht. Der Compiler generiert tatsächlich eine separate statische Klasse und führt eine statische Inline-Initialisierung dieser Klasse durch. Achten Sie besonders auf die Anweisung bei L_0026. Wenn die Klasse bereits initialisiert ist, überspringt die Verzweigung die Add
Anrufe.
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)
Beachten Sie auch, dass das Wörterbuch eine Zuordnung von der ursprünglichen Zeichenkette zu einer Ganzzahl enthält. Diese Ganzzahl wird zur Formulierung eines separaten Schalters in AWL verwendet.
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
Update 2:
Was auch immer es wert ist, VB.NET scheint nicht über die gleiche Optimierung für seine Select
konstruieren.