Подтвердить что ты не робот

Могу ли я использовать отражение для проверки кода в методе?

Я играю с API-интерфейсом С#. Я могу легко загрузить Type информацию о классах, методах и т.д. В сборке, однако теперь мне интересно, как я могу загрузить и прочитать код внутри метода?

4b9b3361

Ответ 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

Ответ 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