[英]Variables ending with “1” have the “1” removed within ILSpy. Why?
为了探索C#编译器如何优化代码,我创建了一个简单的测试应用程序。 每次测试更改,我都编译了应用程序,然后在ILSpy中打开了二进制文件。
我只是注意到一些对我来说很奇怪的东西。 显然这是有意的,但是,我想不出编译器会这么做的一个很好的理由。
请考虑以下代码:
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_1
被优化为test_
! 有没有一个很好的理由为什么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");
}
}
}
}
UPDATE
显然在检查IL之后,这是ILSpy的问题,而不是C#编译器。 Eugene Podskal对我的初步评论和观察给出了很好的答案。 但是,我有兴趣知道这是ILSpy中的错误还是故意功能。
这可能是反编译器的一些问题。 因为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
形式的变量。
编辑:
方法中NameVariables.cs文件中的变量名称变形 :
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;
}
}
NameVariables
类使用this.typeNames
字典来存储没有结束编号的变量名称(这些变量对ILSpy来说是特殊的,或者甚至可能是IL,但实际上我怀疑它)与反编译方法中出现的计数器相关联。
这意味着所有变量( test_1, test_2, test_3
)将在一个槽(“test_”)中结束,而第一个变量count
将为1,从而导致执行:
else {
return nameWithoutDigits;
}
其中nameWithoutDigits
是test_
编辑
首先,感谢@HansPassant和他在这篇文章中指出错误的答案 。
那么,问题的根源:
ILSpy和ildasm一样聪明,因为它也使用.pdb数据(或者它如何获得test_1, test_2
名称)。 但其内部工作方式已经过优化,无需任何调试相关信息即可与程序集一起使用,因此与处理V_0, V_1, V_2
变量相关的优化与.pdb文件中丰富的元数据不一致。
据我所知,罪魁祸首是从单个变量中删除_0
的优化。
修复它可能需要将.pdb数据使用的事实传播到变量名称生成代码中。
嗯,这是一个错误。 没有太大的错误,任何人都不可能提交错误报告。 请注意尤金的答案是非常误导的。 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中的错误所在的位置,它也会读取PDB文件,但会找到它检索到的符号。 您可以向供应商提交错误,但不太可能将它视为高优先级错误。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.