MethodBody.LocalVariables Count сбивает с толку - PullRequest
2 голосов
/ 17 марта 2012

Для простого метода без локальных переменных, подобного следующему

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 Ответ

2 голосов
/ 17 марта 2012

Тот факт, что компилятор 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.

...