MethodBody.LocalVariables Count令人困惑

时间:2012-03-17 00:31:25

标签: c# il local-variables ilgenerator methodbase

对于没有局部变量的简单方法,如下所示

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 WHY?

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。 另外,如果带有j的另一个switch语句将计数保持为2。

1 个答案:

答案 0 :(得分:2)

我认为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代码。