Я играю с API-интерфейсом С#. Я могу легко загрузить Type
информацию о классах, методах и т.д. В сборке, однако теперь мне интересно, как я могу загрузить и прочитать код внутри метода?
Могу ли я использовать отражение для проверки кода в методе?
Ответ 1
Основной ответ:
Вы не можете использовать API отражения (System.Reflection).
Причина в том, что отражение api предназначено для работы над метаданными (тип классов, имя и подпись методов,...), но не на уровне данных (который будет сам IL-поток).
Расширенный ответ:
Вы можете испускать (но не читать) IL с помощью System.Reflection.Emit(например, класса ILGenerator).
Через MethodInfo.GetMethodBody()
вы можете получить бинарный IL-поток для реализации метода. Но это обычно совершенно бесполезно само по себе.
Существуют внешние библиотеки (например Cecil), которые вы можете использовать для чтения/изменения/добавления/удаления кода внутри метода.
Ответ 2
Это зависит от того, что вы подразумеваете, прочитав код. Существует 4 формы кода.
1- Исходный код, например. исходный С# или VB.NET - Нет, вы не можете получить это с отражением
2- Символический код IL - Нет, вы не можете получить это с отражением
3- Код сборки JITed - Нет, вы не можете получить это с отражением
4- байты IL, фактические байты, с которыми скомпилирован IL, получают .
Взгляните на MethodBase.GetMethodBody(), например, вы можете получить байты IL, локальные переменные, кадры исключений и т.д. http://msdn.microsoft.com/en-us/library/system.reflection.methodbase.getmethodbody.aspx
Ответ 3
Теперь есть библиотеки/пакеты, которые позволяют вам проверять код метода и даже декомпилировать его на Expression
:
Ответ 4
Ты вроде как можешь. Соответствующая функция MethodBase.GetMethodBody.
Это не совсем полезный API. Вы можете получить некоторую базовую информацию о том, что внутри метода, и вы можете получить IL как массив байтов. Что об этом.
В библиотеке Mono.Cecil представлен несколько улучшенный API, который предоставляет класс MethodDefinition
со своей собственной реализацией MethodBody
, которая содержит фактический Instructions
, поэтому вам не нужно интерпретировать исходный байтовый код. Тем не менее, если вы хотите получить код С# из него à la Reflector, вы будете сильно разочарованы. Кроме того, Сесил не очень хорошо документирован.
Если вы все еще хотите попробовать, то удачи.
Ответ 5
Если вам не нужно делать это в режиме реального времени, посмотрите Reflector. Вы можете разобрать любую сборку .NET(включая основные DLL файлы MS) и посмотреть код на выбранном вами языке. Это может быть очень образованным.
Обновить. Кто-нибудь пытался использовать Reflector on Reflector, чтобы выяснить, как это делается?
Ответ 6
нетНет
Это функция, предназначенная для следующей версии С#. Вы можете использовать CodeDom, чтобы получить больше информации, чем отражение, но вы еще не можете допросить дерево разбора.
Ну, всегда есть моно, в моно компилятор - это сервис, и вы можете получить деревья синтаксического анализа во время выполнения.
Лучший вопрос - почему вы хотите?
Ответ 7
Да, должен быть способ достижения этого: инструмент .NET Reflector делает это тоже. Не могу сказать, как это там делалось.
Ответ 8
Я хотел бы привести пример того, как можно исследовать код внутри метода. Как объяснили другие, это не может быть легко сделано с помощью собственного .NET Reflection API. Однако, используя API Mono.Reflection, вы можете программно разобрать код с помощью GetInstructions()
и проверить его во время выполнения.
Например, следующий код проверяет метод и вычисляет количество вызовов внутри него. В качестве примера использования такого кода, скажем, что я учитель (которым я являюсь) и инструктирую своих сокурсников программировать данный метод без использования какого-либо другого метода, затем, используя этот код в модульных тестах, я могу проверить, что данное ограничение уважал.
public static class MethodInfoUtil
{
public static int NbOfInnerCalls(this MethodInfo mi)
{
return mi.GetInstructions().Count(
instruction => instruction.OpCode.FlowControl == FlowControl.Call);
}
}
Пример консольной программы:
class Program
{
static int Add(int a, int b) => a + b;
static int Doubling(int a) => Add(a, a);
static int Quadrupling(int a) => Add(Add(a, a), Add(a, a));
static void Main(string[] args)
{
Console.WriteLine("Inner method calls");
Console.WriteLine(" Add: {0}", ((Func<int, int, int>)Add).Method.NbOfInnerCalls());
Console.WriteLine(" Doubling: {0}", ((Func<int, int>)Doubling).Method.NbOfInnerCalls());
Console.WriteLine("Quadrupling: {0}", ((Func<int, int>)Quadrupling).Method.NbOfInnerCalls());
}
}
// Output:
// Inner method calls
// Add: 0
// Doubling: 1
// Quadrupling: 3