如果我有这样的代码:
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
只有三个属性:IsPinned
,LocalIndex
和LocalType
。所以没有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
来获取变量名称。如果我想获取包括编译器生成的临时变量在内的所有本地文件,它就不起作用。
答案 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,其中指定了方法的局部变量签名(所有局部变量的列表)的二进制格式。并且它不包含任何变量名称:
因此,如果某个工具想要知道局部变量的原始名称,则必须查看PDB文件中包含的调试信息。如果不存在,则无法找到名称。
答案 2 :(得分:4)
来自MSDN:
本地变量名称不会保留在元数据中。在Microsoft中间语言(MSIL)中,局部变量通过它们在局部变量签名中的位置来访问。
答案 3 :(得分:2)
我认为这是因为您在ILDasm中看到的变量名来自pdb文件,而不是来自程序集本身。如果你想获得它们,你也需要阅读pdb。