Почему невозможно получить имена локальных переменных с помощью Reflection?
Если у меня есть такой код:
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;
Это возвращает a 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
для получения имени переменной. Это не работает, если я хотел бы получить все локальные жители, включая временные переменные, сгенерированные компилятором.
Ответы
Ответ 1
Вы должны различать понятную для человека текстовую форму CLI и машиночитаемую скомпилированную форму CLI.
В текстовом CLI локальные переменные действительно могут иметь имена (см. §II.15.4.1.3 ECMA-335, как объяснено в ответе Дэмиена).
Но в двоичной форме локальные переменные не имеют имен. Для этого рассмотрим §II.23.2.6, где указан бинарный формат для локальной сигнатуры локальной переменной метода (список всех ее локальных переменных). И он не содержит упоминания имен переменных:
![LocalVarSig]()
Итак, если какой-либо инструмент хочет узнать исходное имя локальной переменной, он должен изучить информацию об отладке, содержащуюся в файле PDB. Если этого нет, нет способа узнать имя.
Ответ 2
Я думаю, вы смотрите на сборку Debug. Часть id
объявления .locals
является необязательной, поэтому нет гарантии, что имена сохранены.
См. MS Partition II, в котором более подробно описаны метаданные IL, раздел 15.4.1.3:
MethodBodyItem ::= …
.locals [ init ] ‘(’ LocalsSignature ‘)’
LocalsSignature ::= Local [ ‘,’ Local ]*
Local ::= Type [ Id ]
Ответ 3
Из MSDN:
Локальные имена переменных не сохраняются в метаданных. В промежуточном языке Microsoft (MSIL) доступ к локальным переменным осуществляется по их позиции в локальной сигнатуре переменной.
Ответ 4
Я думаю, это потому, что имя переменной, которое вы видите в ILDasm, происходит из файла pdb, а не из самой сборки. Если вы хотите их получить, вам также нужно будет прочитать pdb.