wake-up-neo.net

C # Reflexion und alle Referenzen finden

Mit einer DLL -Datei möchte ich alle Aufrufe einer Methode in dieser DLL -Datei finden können. Wie kann ich das machen?

Wie kann ich programmgesteuert tun, was Visual Studio bereits tut?

Ich möchte kein Tool wie .NET Reflector verwenden, um dies zu tun, aber Reflexion ist in Ordnung und wahrscheinlich notwendig.

35
user420667

Um herauszufinden, wo eine Methode MyClass.Foo() verwendet wird, müssen Sie alle Klassen aller Assemblys analysieren, die über eine Referenz auf die Assembly verfügen, die MyClass enthält. Ich habe einen einfachen Proof of Concept geschrieben, wie dieser Code aussehen kann. In meinem Beispiel habe ich diese Bibliothek (es ist nur eine einzige .cs-Datei ) von Jb Evain geschrieben:

Ich habe einen kleinen Testkurs geschrieben, um 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 in TestClass.Test() verwendeten Methoden auszudrucken:

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())
        );
    }
}

Es gab mir 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 offensichtlich noch lange nicht abgeschlossen, da es keine ref- und out-Parameter und keine generischen Argumente behandelt. Ich bin sicher, dass auch andere Details vergessen wurden. Es zeigt nur, dass es möglich ist.

46
Elian Ebbing

Die Reflexion allein reicht nicht aus, um alle Verweise auf eine Methode in einer gegebenen Assembly zu finden. Reflection gibt Ihnen ein Byte-Array für den Rumpf einer bestimmten Methode ( MethodInfo.GetMethodBody.GetILAsByteArray ), und Sie müssen es selbst auf Verweise auf andere Methoden analysieren. Es gibt mehrere öffentlich verfügbare Bibliotheken " CIL reader" (die ich nicht verwendet habe - hoffentlich wird jemand mehr dazu posten).

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

3
Alexei Levenkov

Sie können einen Blick auf den MSDN Magazine-Artikel Bestimmen von .NET-Assembly- und Methodenreferenzen werfen.

2
Darin Dimitrov

Ich würde mir überlegen, die Visual Studio-Assemblys zu reflektieren und zu sehen, ob Sie sie in der Reverse Engineered Code Base finden können. Ich glaube, dass VS tatsächlich durch Code navigiert und nicht reflektiert. Die Reflexion ist, wie Michael berichtet hat, großartig, um die Teile einer Baugruppe zu bestimmen, nicht aber die Verbraucher dieser Teile. Ich habe das Nachdenken jedoch nicht noch einmal geprüft, um meinen Verdacht zu bestätigen.

1

Dies ist ein Beispiel, wenn Sie nach allen Anrufen in der aktuellen Assembly suchen möchten. Ich habe dies so programmiert, dass versucht wurde, einen Parameterwert abzurufen, um einige Einschränkungen für eine Methode mit einigen Standardwerten festzulegen. Es gelang mir jedoch nicht, die Parameterwerte zu erhalten, ich erhielt 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.