Скомпилируйте следующий код.
public static int Main(string[] args)
{
switch (args[0])
{
case "x": return 1;
case "y": return 2;
case "z": return 3;
}
return 0;
}
Теперь используйте Отражатель или ILDASM для проверки IL, генерируемого компилятором C #.Продолжайте добавлять операторы case и декомпилировать и наблюдать за результатом.
- Если число операторов case мало, компилятор выдает последовательное сравнение на равенство.
- Если число операторов case равноПри больших значениях компилятор выполняет поиск
Dictionary
.
Я использовал компилятор C # 3.0 и заметил, что стратегия меняется на 7 операторах case.Я подозреваю, что вы увидите что-то похожее с C # 4.0 и другими.
Обновление:
Я должен указать, что вы увидите вызовы Dictionary.Add
на выходе IL, гдеэто создание словаря для последующего использования.Не обманывайте себя, думая, что это происходит каждый раз.Компилятор фактически генерирует отдельный статический класс и выполняет его статическую статическую инициализацию.Обратите особое внимание на инструкцию на 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
конструкции.