43 Stimmen

C#-Reflexion und Auffinden aller Referenzen

Wenn ich eine DLL-Datei habe, möchte ich alle Aufrufe einer Methode in dieser DLL-Datei finden können. Wie kann ich das tun?

Wie kann ich im Wesentlichen programmatisch tun, was Visual Studio bereits tut?

Ich möchte nicht ein Tool wie .NET-Reflektor zu tun, aber Nachdenken ist gut und wahrscheinlich notwendig.

56voto

Elian Ebbing Punkte 17941

Um herauszufinden, wo eine Methode MyClass.Foo() verwendet wird, müssen Sie alle Klassen aller Baugruppen analysieren, die einen Verweis auf die Baugruppe haben, die die MyClass . Ich habe ein einfaches Beispiel dafür geschrieben, wie dieser Code aussehen kann. In meinem Beispiel habe ich diese Bibliothek (es ist nur eine einzelne .cs-Datei ), geschrieben von Jb Evain:

Ich habe eine kleine Testklasse geschrieben, um sie zu analysieren:

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

Und ich habe diesen Code geschrieben, um alle Methoden auszugeben, die in 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())
        );
    }
}

Ich erhielt die folgende Ausgabe:

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

Dieses Beispiel ist natürlich bei weitem nicht vollständig, da es weder ref- noch out-Parameter und auch keine generischen Argumente handhabt. Ich bin sicher, dass ich auch andere Details vergessen habe. Es zeigt nur, dass es machbar ist.

5voto

Darin Dimitrov Punkte 990883

Werfen Sie einen Blick auf den Artikel im MSDN Magazine Ermitteln von .NET Assembly- und Methodenreferenzen .

3voto

Alexei Levenkov Punkte 96742

Reflection allein reicht nicht aus, um alle Verweise auf eine Methode in einer bestimmten Assembly zu finden. Reflection gibt Ihnen ein Byte-Array für den Körper einer bestimmten Methode ( MethodInfo.GetMethodBody.GetILAsByteArray ) und Sie müssen sie selbst nach Verweisen auf andere Methoden durchsuchen. Es gibt mehrere öffentlich verfügbare " CIL Reader"-Bibliotheken (ich habe sie nicht benutzt - hoffentlich wird jemand mehr darüber schreiben).

Hinzufügen von FxCop Option - je nach Ihrem Szenario können Sie die von FxCop (Visual Studio Code Analysis) bereitgestellte CIL-Parsing-Logik wiederverwenden und Ihre eigenen Regeln hinzufügen, wenn die Ausführung als Teil der Codeanalyse für Sie in Ordnung ist.

1voto

Gregory A Beamer Punkte 16670

Ich würde erwägen, die Visual Studio-Assemblies zu spiegeln und zu sehen, ob Sie es in der zurückentwickelten Codebasis finden können. Ich glaube, VS ist eigentlich navigieren Code statt reflektieren. Reflection, wie Michael gepostet hat, ist großartig für die Bestimmung der Bits einer Baugruppe, aber nicht die Verbraucher von diesen Bits. Ich habe Reflection jedoch nicht erneut untersucht, um meinen Verdacht zu bestätigen.

0voto

Hey, dies ist ein Beispiel unter der Annahme, dass Sie nach allen Aufrufen in der aktuellen Baugruppe suchen möchten. Ich habe dies programmiert, um einen Parameterwert zu erhalten, um einige Einschränkungen für eine Methode mit einigen Standardwerten zu setzen. Aber ich konnte nicht verwalten, um die Parameterwerte zu erhalten, ich bekam nur Typen und Standardwerte.

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.
}

Ich hoffe, es hilft.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X