为什么不能使用Reflection获取局部变量名?

时间:2014-10-20 10:29:23

标签: c# reflection local-variables il

如果我有这样的代码:

public class Program
{
    public static void Main()
    {
        string bar = "";
        int foo = 24;
    }
}

我可以使用:

获取Main中声明的局部变量
var flag = BindingFlags.Static | BindingFlags.Public;
var fields = typeof(Program).GetMethod("Main", flags).GetMethodBody().LocalVariables;

这会返回IList<LocalVariableInfo>,而LocalVariableInfo只有三个属性:IsPinnedLocalIndexLocalType。所以没有Name财产存在。

我想知道的是,您可以在生成的IL code中看到变量名称:

.method public hidebysig static void  Main() cil managed
{
  .entrypoint
  // Code size       11 (0xb)
  .maxstack  1
  .locals init ([0] string bar,
           [1] int32 foo)
  IL_0000:  nop
  IL_0001:  ldstr      ""
  IL_0006:  stloc.0
  IL_0007:  ldc.i4.s   24
  IL_0009:  stloc.1
  IL_000a:  ret
} // end of method Program::Main

但是不可能使用Reflection来获取它们。是不是因为局部变量没有名称而且只能通过索引访问它们(如果是ILDASM.exe如何显示名称?),还是因为没有实现这样的功能?或者,如果可以使用其他方式,则问题是

注意:我看过一些像this这样的问题,其中大部分都是使用Expressions来获取变量名称。如果我想获取包括编译器生成的临时变量在内的所有本地文件,它就不起作用。

4 个答案:

答案 0 :(得分:6)

我认为您正在查看Debug构建。 id声明的.locals部分是可选 - 因此无法保证名称被保留。

有关详细信息,请参阅描述IL元数据的MS Partition II,第15.4.1.3节:

MethodBodyItem ::= …
   .locals [ init ] ‘(’ LocalsSignature ‘)’
LocalsSignature ::= Local [ ‘,’ Local ]*
Local ::= Type [ Id ]

答案 1 :(得分:6)

您必须区分基于人类可读文本的CLI形式和机器可读的CLI编译形式。

在文本CLI中,局部变量确实可以有名称(参见ECMA-335的§II.15.4.1.3,如Damien的答案中所述)。

但是在二进制形式中,局部变量没有名称。为此,请查看§II.23.2.6,其中指定了方法的局部变量签名(所有局部变量的列表)的二进制格式。并且它不包含任何变量名称:

LocalVarSig

因此,如果某个工具想要知道局部变量的原始名称,则必须查看PDB文件中包含的调试信息。如果不存在,则无法找到名称。

答案 2 :(得分:4)

来自MSDN

  

本地变量名称不会保留在元数据中。在Microsoft中间语言(MSIL)中,局部变量通过它们在局部变量签名中的位置来访问。

答案 3 :(得分:2)

我认为这是因为您在ILDasm中看到的变量名来自pdb文件,而不是来自程序集本身。如果你想获得它们,你也需要阅读pdb。