Могу ли я использовать рефлексию для проверки кода в методе? - PullRequest
37 голосов
/ 22 апреля 2010

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

Ответы [ 7 ]

33 голосов
/ 22 апреля 2010

Основной ответ:

Вы не можете использовать API отражения (System.Reflection).

Причина в том, что API отражения предназначен для работы сМетаданные (тип классов, название и подпись методов, ...), но не на уровне данных (который будет представлять собой сам поток IL).

Расширенный ответ:

Вы можете генерировать (но не читать) IL с помощью System.Reflection.Emit (например, ILGenerator Class).

Через MethodInfo.GetMethodBody() вы можете получить двоичный IL-поток для реализации метода.Но это обычно совершенно бесполезно само по себе.

Существуют внешние библиотеки (например, Cecil ), которые можно использовать для чтения / изменения / добавления / удаления кода внутри метода.

16 голосов
/ 22 апреля 2010

Это зависит от того, что вы подразумеваете под прочтением кода. Существует 4 формы кода.

1- Исходный код, например. оригинальный C # или VB.NET - нет, вы не можете получить это с отражением
2- Символический код IL - Нет, вы не можете получить это с отражением
3- Код сборки JITed - Нет, вы не можете получить это с отражением

4- Байты IL, фактические байты, к которым компилируется IL, которые вы можете получить.

Взгляните на MethodBase.GetMethodBody (). Например, вы можете получить байты IL, локальные переменные, фреймы исключений и т. Д. http://msdn.microsoft.com/en-us/library/system.reflection.methodbase.getmethodbody.aspx

9 голосов
/ 22 апреля 2010

Вы вроде можете.Соответствующая функция: MethodBase.GetMethodBody .

Это не совсем самый полезный API.Вы можете получить некоторую основную информацию о том, что находится внутри метода, и вы можете получить IL в виде байтового массива.Вот и все.

В библиотеке Mono.Cecil есть немного лучший API, который предоставляет класс MethodDefinition со своей собственной реализацией MethodBody, которая содержит фактическую Instructions, поэтомуВам не нужно интерпретировать необработанный байт-код.Тем не менее, если вы хотите получить код C # из него, как Reflector, вы будете сильно разочарованы.Кроме того, Сесил не очень хорошо задокументирован.

Если вы все еще хотите попробовать, тогда удачи.

2 голосов
/ 22 апреля 2010

Если вам не нужно делать это в реальном времени, взгляните на Reflector . Вы можете дизассемблировать любую сборку .NET (включая библиотеки ядра MS) и просматривать код на выбранном вами языке. Это может быть очень образовательных.

Обновление Кто-нибудь пробовал использовать Reflector на Reflector, чтобы выяснить, как это делается?

1 голос
/ 22 апреля 2010

Да, должен быть способ достичь этого: инструмент .NET Reflector также делает это.Хотя не могу сказать, как там это делается.

1 голос
/ 22 апреля 2010

Нет
Эта функция предназначена для следующей версии C #.Вы можете использовать CodeDom, чтобы получить больше информации, чем отражения, но пока не можете опросить дерево разбора.

Ну, всегда есть моно, в моно компилятор - это служба, и вы можете получить деревья разбора во время выполнения.

Лучший вопрос, почему вы хотите?

0 голосов
/ 05 июня 2019

Я хотел бы привести пример того, как можно исследовать код внутри метода.Как объяснили другие, это не может быть легко сделано с помощью собственного .NET Reflection API.Однако, используя Mono.Reflection API, вы можете программно разобрать код с помощью метода 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...