C# 以“结束”结尾的变量;1“;有",;1“;在ILSpy中删除。为什么?

C# 以“结束”结尾的变量;1“;有",;1“;在ILSpy中删除。为什么?,c#,ilspy,C#,Ilspy,为了探索C#编译器如何优化代码,我创建了一个简单的测试应用程序。每次测试更改后,我都会编译应用程序,然后在ILSpy中打开二进制文件 private static void Main(string[] args) { int test_ = 1; //Where did the "1" go at the end of the variable name??? int test_2 = 0; int test_3 = 0; if (test_ == 1)

为了探索C#编译器如何优化代码,我创建了一个简单的测试应用程序。每次测试更改后,我都会编译应用程序,然后在ILSpy中打开二进制文件

private static void Main(string[] args)
{
    int test_ = 1; //Where did the "1" go at the end of the variable name???
    int test_2 = 0;
    int test_3 = 0;
    if (test_ == 1)
    {
        Console.Write(1);
    }
    else
    {
        if (test_2 == 1)
        {
            Console.Write(1);
        }
        else
        {
            if (test_3 == 1)
            {
                Console.Write(2);
            }
            else
            {
                Console.Write("x");
            }
        }
    }
}
我只是注意到一些对我来说很奇怪的事情。显然这是故意的,但是,我想不出一个好的理由来解释为什么编译器会这样做

考虑以下代码:

static void Main(string[] args)
{
    int test_1 = 1;
    int test_2 = 0;
    int test_3 = 0;

    if (test_1 == 1) Console.Write(1);
    else if (test_2 == 1) Console.Write(1);
    else if (test_3 == 1) Console.Write(2);
    else Console.Write("x");
}
毫无意义的代码,但我写这篇文章是为了看看ILSpy将如何解释
if
语句

然而,当我编译/反编译这段代码时,我确实注意到一些让我抓狂的事情。我的第一个变量
test\u 1
优化为
test\u
!C#编译器这样做有什么好的理由吗

为了进行全面检查,这是我在ILSpy中看到的
Main()
的输出

private static void Main(string[] args)
{
    int test_ = 1; //Where did the "1" go at the end of the variable name???
    int test_2 = 0;
    int test_3 = 0;
    if (test_ == 1)
    {
        Console.Write(1);
    }
    else
    {
        if (test_2 == 1)
        {
            Console.Write(1);
        }
        else
        {
            if (test_3 == 1)
            {
                Console.Write(2);
            }
            else
            {
                Console.Write("x");
            }
        }
    }
}
更新


显然,在检查了IL之后,这是ILSpy的问题,而不是C#编译器的问题。尤金·波德斯卡尔对我最初的评论和观察给出了一个很好的答案。然而,我很想知道这是ILSpy内部的一个bug,还是有意的功能。

这可能是反编译器的一些问题。因为IL在.NET 4.5 VS2013上是正确的:

.entrypoint
  // Code size       79 (0x4f)
  .maxstack  2
  .locals init ([0] int32 test_1,
           [1] int32 test_2,
           [2] int32 test_3,
           [3] bool CS$4$0000)
  IL_0000:  nop
  IL_0001:  ldc.i4.1
  IL_0002:  stloc.0
编辑:它使用.pdb文件中的数据(请参阅)获取正确的名称变量。如果没有pdb,它将具有
V_0、V_1、V_2
形式的变量

编辑:

方法中的文件中的变量名损坏:

public string GetAlternativeName(string oldVariableName)
{
    if (oldVariableName.Length == 1 && oldVariableName[0] >= 'i' && oldVariableName[0] <= maxLoopVariableName) {
        for (char c = 'i'; c <= maxLoopVariableName; c++) {
            if (!typeNames.ContainsKey(c.ToString())) {
                typeNames.Add(c.ToString(), 1);
                return c.ToString();
            }
        }
    }

    int number;
    string nameWithoutDigits = SplitName(oldVariableName, out number);

    if (!typeNames.ContainsKey(nameWithoutDigits)) {
        typeNames.Add(nameWithoutDigits, number - 1);
    }

    int count = ++typeNames[nameWithoutDigits];

    if (count != 1) {
        return nameWithoutDigits + count.ToString();
    } else {
        return nameWithoutDigits;
    }
}
其中
无数字名称
测试

编辑

首先,感谢你在这篇文章中指出错误

因此,问题的根源是:

ILSpy与ildasm一样智能,因为它也使用.pdb数据(或者它如何获得
test\u 1、test\u 2
名称)。但是,它的内部工作是针对没有任何调试相关信息的程序集进行优化的,因此它与处理
V_0、V_1、V_2
变量相关的优化与.pdb文件中丰富的元数据不一致

据我所知,罪魁祸首是从单个变量中删除
\u 0
的优化


修复它可能需要将.pdb数据使用的事实传播到变量名生成代码中。

嗯,这是一个bug。不算什么bug,几乎不可能有人为此提交bug报告。请注意,尤金的回答非常误导。ildasm.exe足够聪明,知道如何定位程序集的PDB文件并检索程序集的调试信息。其中包括局部变量的名称

这通常不是拆卸器可以使用的奢侈品。这些名称实际上并不存在于程序集本身中,它们总是必须在没有PDB的情况下使用。您也可以在ildasm.exe中看到,只需删除obj\Release和bin\Release目录中的.pdb文件,现在看起来如下所示:

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       50 (0x32)
  .maxstack  2
  .locals init (int32 V_0,
           int32 V_1,
           int32 V_2)
  IL_0000:  ldc.i4.1
  // etc...
V_0
V_1
等名字当然不是很好,反汇编程序通常会想出更好的方法。有点像“num”


因此,有点清楚ILSpy中的bug所在的位置,它也读取PDB文件,但却在检索符号时出错。您可以向供应商提交错误,但他们不太可能将其视为高优先级错误。

是的,他们是。这就是为什么您可以编译/反编译程序集,并查看指定反编译代码的完整代码。这是由ILSpy之类的IL解释器完成的,它可以将编译后的.Net程序集输出到您选择的任何.Net语言。这决不能发生,至少不是通过自身或编译器。让我检查ildasm中的IL…@AfzaalAhmadZeeshan我能够使用发布的代码复制此内容。这是ILSpy的问题,或者更一般地说是反编译器的问题
dotPeek
显示变量名称的
num1
num2
num3
。谢谢。这就是答案——我应该更进一步。当我检查IL时,我自己发现了这个我猜这是ILSpy中的一个bug。看到这一点,我们可能看到反编译器正在删除“1”,因为某些带下划线的名称似乎是“maical”——例如由“property{get;set;}”或lambdasI生成的匿名字段会删除这个问题,但由于许多人使用ILSpy,我把它留着以后参考。您将在大约5分钟内得到答案。@EugenePodskal我已更新了我的问题,以反映ILSpy内部的好奇心。还有,事实上,有人否决了我?有时候我不明白,谢谢你,汉斯。你的答案总是很有用的!