.Net 4 (или какая-либо предыдущая версия) выполняют какой-либо вид оптимизации на более длительных операторах переключения на основе строк?
Я работаю вокруг потенциального узкого места производительности из-за некоторых долгих операторов переключения, ища соответствующие строки в случаях, и я всегда предполагал, что они ищутся в линейное время (или почти линейные, т.е. не использование индекса для быстрого нахождения соответствующей строки). Но это походит на очевидную область, которую мог оптимизировать .NET, поэтому думал, что я проверю, если это верно, или нет.
Это - производный вопрос от моего недавнего: индексируемый оператор переключения, или эквивалентный? .NET, C#
Скомпилируйте следующий код.
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 , чтобы проверить IL, генерируемый компилятором C #. Продолжайте добавлять операторы case и декомпилировать и наблюдать за результатом.
Dictionary
. Я использовал компилятор C # 3.0 и заметил, что стратегия меняется в 7 случаях. Я подозреваю, что вы увидите что-то похожее на C # 4.0 и другие.
Обновление:
Я должен указать, что вы увидите вызовы Dictionary.Add
в выводе IL, где он создает словарь для дальнейшего использования. Не обманывайтесь, думая, что это происходит каждый раз. Компилятор фактически создает отдельный статический класс и выполняет его встроенную статическую инициализацию. Обратите особое внимание на инструкцию на L_0026. Если класс уже инициализирован, ветвь будет пропускать вызовы Добавить
.
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
.