C # отражение и поиск всех ссылок - PullRequest
36 голосов
/ 30 марта 2011

Учитывая файл DLL, я хотел бы иметь возможность найти все вызовы метода в этом файле DLL.Как я могу это сделать?

По сути, как я могу программно делать то, что Visual Studio уже делает?

Я не хочу использовать такой инструмент, как .NET Reflector чтобы сделать это, но рефлексия в порядке и, вероятно, необходимо.

Ответы [ 6 ]

48 голосов
/ 30 марта 2011

Чтобы выяснить, где используется метод MyClass.Foo(), необходимо проанализировать все классы всех сборок, которые имеют ссылку на сборку, содержащую MyClass. Я написал простое доказательство того, как этот код может выглядеть. В моем примере я использовал эту библиотеку (это просто единственный файл .cs ), написанный Jb Evain:

Я написал небольшой тестовый класс для анализа:

public class TestClass
{
    public void Test()
    {
        Console.WriteLine("Test");
        Console.Write(10);
        DateTime date = DateTime.Now;
        Console.WriteLine(date);
    }
}

И я написал этот код, чтобы распечатать все методы, используемые в TestClass.Test():

MethodBase methodBase = typeof(TestClass).GetMethod("Test");
var instructions = MethodBodyReader.GetInstructions(methodBase);

foreach (Instruction instruction in instructions)
{
    MethodInfo methodInfo = instruction.Operand as MethodInfo;

    if(methodInfo != null)
    {
        Type type = methodInfo.DeclaringType;
        ParameterInfo[] parameters = methodInfo.GetParameters();

        Console.WriteLine("{0}.{1}({2});",
            type.FullName,
            methodInfo.Name,
            String.Join(", ", parameters.Select(p => p.ParameterType.FullName + " " + p.Name).ToArray())
        );
    }
}

Это дало мне следующий вывод:

System.Console.WriteLine(System.String value);
System.Console.Write(System.Int32 value);
System.DateTime.get_Now();
System.Console.WriteLine(System.Object value);

Этот пример явно далек от завершения, потому что он не обрабатывает параметры ref и out и не обрабатывает общие аргументы. Я уверен, что забыл и о других деталях. Это просто показывает, что это можно сделать.

3 голосов
/ 30 марта 2011

Одного отражения недостаточно, чтобы найти все ссылки на метод в данной сборке.Reflection дает вам байтовый массив для тела любого конкретного метода ( MethodInfo.GetMethodBody.GetILAsByteArray ), и вы должны проанализировать его самостоятельно для ссылок на другие методы.Существует несколько общедоступных библиотек " CIL reader" (я ими не пользовался - надеюсь, кто-то опубликует больше об этом).

Добавление FxCop - в зависимости отВ вашем сценарии вы можете повторно использовать логику синтаксического анализа CIL, предоставляемую FxCop (анализ кода Visual Studio), и добавлять свои пользовательские правила, если для вас это нормально, если вы выполняете его как часть анализа кода.

2 голосов
/ 30 марта 2011

Вы можете взглянуть на статью MSDN Magazine Определение ссылок на сборки и методы .NET .

1 голос
/ 30 марта 2011

Я бы подумал об отражении сборок Visual Studio и посмотрю, сможете ли вы найти его в базе кода с обратным инжинирингом.Я считаю, что VS на самом деле является навигационным кодом, а не отражением.Отражение, как писал Майкл, отлично подходит для определения битов сборки, но не для потребителей этих битов.Однако я не пересмотрел свое мнение, чтобы подтвердить свои подозрения.

0 голосов
/ 11 июня 2018

Эй, это пример, если вы хотите найти все вызовы в текущей сборке. Я закодировал это, пытаясь получить значение параметра, чтобы установить некоторые ограничения для метода с некоторыми значениями по умолчанию. Но мне не удалось получить значения параметров, я получил только типы и значения по умолчанию.

var currentAssembly = Assembly.GetExecutingAssembly();

foreach (var method in currentAssembly.GetTypes().Where(type => type.IsClass)
                                      .SelectMany(cl => cl.GetMethods())
                                      .OfType<MethodBase>()
                                      .SelectMany(mb => mb.GetInstructions())
                                      .Select(inst => inst.Operand).OfType<MethodInfo>()
                                      .Where(mi => mi.Name == "<YourMethodName>"))
{
    //here are your calls.
}

Надеюсь, это поможет.

0 голосов
/ 30 марта 2011

См. Вопрос переполнения стека Получить список функций для DLL .

Извлечено из вышеизложенного (спасибо Джону Скиту):

Для конкретной сборки вы можете использовать Assembly.GetTypes для получения типов, затем для каждого типа вызывать Type.GetMethods (), Type.GetProperties () и т. Д. Или просто Type.GetMembers ().

Однако для функциональности плагинов, как правило, хорошей идеей является наличие общего интерфейса, который должны быть реализованы плагинами, - который уменьшает количество отражений, которые вам необходимо использовать.Используйте Type.IsAssignableFrom (), чтобы проверить, совместим ли тип с конкретным интерфейсом.

Возможно, вы также захотите взглянуть на платформу Managed Extensibility Framework, которая может упростить реализацию системы расширений.

...