C # reflection e encontrar todas as referências

Dado um arquivo DLL, gostaria de poder encontrar todas as chamadas para um método dentro desse arquivo DLL. Como posso fazer isso?

Essencialmente, como posso fazer programaticamente o que o Visual Studio já faz?

Eu não quero usar uma ferramenta como o .NET Reflector para fazer isso, mas a reflection é boa e provavelmente necessária.

Para descobrir onde um método MyClass.Foo() é usado, você deve analisar todas as classs de todos os assemblies que têm uma referência ao assembly que contém MyClass . Eu escrevi uma simples prova de conceito de como esse código pode parecer. No meu exemplo eu usei essa biblioteca (é apenas um arquivo .cs simples ) escrito por Jb Evain:

Eu escrevi uma pequena aula de teste para analisar:

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

E eu escrevi este código para imprimir todos os methods usados ​​em 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()) ); } } 

Isso me deu a seguinte saída:

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

Este exemplo está obviamente longe de ser completo, porque não manipula os parâmetros ref e out e não manipula argumentos genéricos. Tenho certeza de que também se esqueceu de outros detalhes. Isso só mostra que isso pode ser feito.

A reflection sozinha não é suficiente para encontrar todas as referências a um método em uma determinada assembly. Reflexão fornece uma matriz de bytes para o corpo de qualquer método específico ( MethodInfo.GetMethodBody.GetILAsByteArray ) e você tem que analisá-lo por referências a outros methods. Existem várias bibliotecas ” CIL reader” publicamente disponíveis (eu não as usei – espero que alguém publique mais sobre ela).

Adicionando a opção FxCop – dependendo do seu cenário, você poderá reutilizar a lógica de análise CIL fornecida pelo FxCop (análise de código do Visual Studio) e adicionar suas regras personalizadas, se a execução como parte da análise de código estiver correta para você.

Você pode dar uma olhada no artigo da MSDN Magazine Determinando o .NET Assembly e Referências de Método .

Eu consideraria refletir os assemblies do Visual Studio e ver se você pode encontrá-lo na base de código engenharia reversa. Acredito que VS esteja realmente navegando em código em vez de refletir. A reflection, como Michael postou, é ótima para determinar os bits de uma assembly, mas não os consumidores desses bits. Eu não reexaminei a reflection para confirmar minhas suspeitas, no entanto.

Ei, este é um exemplo supondo que você deseja procurar todas as chamadas na assembly atual. Codifiquei isso tentando obter um valor de parâmetro para definir algumas restrições para um método com alguns valores padrão. Mas não consegui obter os valores dos parâmetros, só tenho tipos e padrões.

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

Espero que ajude.

Veja a questão de estouro de pilha Obter uma lista de funções para uma DLL .

Rasgado do acima (obrigado Jon Skeet):

Para uma assembly específica, você pode usar Assembly.GetTypes para obter os tipos e, em seguida, para cada tipo, digite Type.GetMethods (), Type.GetProperties () etc ou apenas Type.GetMembers ().

No entanto, para a funcionalidade do plug-in, geralmente é uma boa ideia ter uma interface comum que os plug-ins devem implementar – isso reduz a quantidade de reflexo que você precisa usar. Use Type.IsAssignableFrom () para verificar se um tipo é compatível com uma interface específica.

Você também pode querer examinar o Managed Extensibility Framework, que pode facilitar a implementação de um sistema de extensão.