MethodBody.LocalVariables Count сбивает с толку
Для простого метода без локальных переменных, подобного следующему
public static int Test1(short i, long j)
{
j = i + j;
switch (j)
{
case 1:
j = 2;
break;
default:
j = 11;
break;
}
return j;
}
Количество MethodInfo.GetMethodBody().LocalVariables.Count = 2 ПОЧЕМУ? Добавьте еще один оператор switch, и счет станет 3 ПОЧЕМУ?
public static int Test1(short i, long j)
{
j = i + j;
switch (j)
{
case 1:
j = 2;
break;
default:
j = 11;
break;
}
switch (i)
{
case 1:
j = 2;
break;
default:
j = 11;
break;
}
return j;
}
Локальные переменные не определены. Так почему 2 и 3. Кроме того, если другой оператор switch с j сохраняет счет на 2.
1 ответ
Думаю, следует ожидать, что компилятор C# генерирует локальные переменные, которых нет в исходном коде C#. Это потому, что стек IL не всегда является отличным местом для хранения некоторых временных значений, потому что вы можете получить доступ только к его вершине.
И это особенно относится к отладочным сборкам, потому что они оптимизированы для отладки, а не для производительности или использования памяти. Я понятия не имею, как эти местные жители помогают отладчику, или помогают ли они вообще, но я предполагаю, что они действительно имеют свою точку зрения.
В частности, ваш метод на самом деле не будет компилироваться, как указал jmh_gr, потому что вы не можете неявно приводить long
в int
, Если я изменю тип j
в int
, он создает такой код при использовании конфигурации отладки (декомпилируется с помощью Reflector, с отключенной оптимизацией):
public static int Test1(short i, int j)
{
int CS$1$0000;
int CS$4$0001;
j = i + j;
CS$4$0001 = j;
if (CS$4$0001 != 1)
{
goto Label_0013;
}
j = 2;
goto Label_0019;
Label_0013:
j = 11;
Label_0019:
CS$1$0000 = j;
Label_001D:
return CS$1$0000;
}
Итак, вы видите, метод на самом деле имеет два локальных, и оба используются. При использовании конфигураций выпуска у сгенерированного IL есть только одна локальная переменная, и это выглядит так:
public static int Test1(short i, int j)
{
int CS$0$0000;
j = i + j;
CS$0$0000 = j;
if (CS$0$0000 != 1)
{
goto Label_0010;
}
j = 2;
goto Label_0014;
Label_0010:
j = 11;
Label_0014:
return j;
}
Похоже, что местные не должны быть необходимыми, но, возможно, есть веская причина для этого. И, конечно, для производительности действительно важна компиляция JIT, а не код IL.