8 Stimmen

Wie man IL zur Laufzeit in eine Methode einfügt

Der Titel sagt eigentlich schon alles. Basierend auf diesem Artikel, habe ich folgendes entwickelt:

public static unsafe void Replace(this MethodBase destination, MethodBase source)
{
    IntPtr srcHandle = source.MethodHandle.GetFunctionPointer();
    IntPtr dstHandle = destination.MethodHandle.GetFunctionPointer();

    int* dstPtr = (int*)dstHandle.ToPointer();
    *dstPtr = srcHandle.ToInt32();
}

Das funktioniert tatsächlich... gelegentlich -.-

Zum Beispiel, dies funktioniert.

public static class Program
{
    public static void Main(string[] args)
    {
        MethodInfo methodA = typeof(Program).GetMethod("A", BindingFlags.Public | BindingFlags.Static);
        MethodInfo methodB = typeof(Program).GetMethod("B", BindingFlags.Public | BindingFlags.Static);

        methodA.Replace(methodB);

        A();
        B();
    }

    public static void A()
    {
        Console.WriteLine("Hallo Welt");
    }

    public static void B()
    {
        Console.WriteLine("Tschüss Welt");
    }
}

Jedoch funktioniert dies nicht (SEHException). Alles, was ich gemacht habe, war, die Reihenfolge zu ändern, in der die Funktionen definiert wurden.

public static class Program
{
    public static void Main(string[] args)
    {
        MethodInfo methodA = typeof(Program).GetMethod("A", BindingFlags.Public | BindingFlags.Static);
        MethodInfo methodB = typeof(Program).GetMethod("B", BindingFlags.Public | BindingFlags.Static);

        methodA.Replace(methodB);

        A();
        B();
    }

    public static void B()
    {
        Console.WriteLine("Tschüss Welt");
    }

    public static void A()
    {
        Console.WriteLine("Hallo Welt");
    }
}

Was den Code im Artikel betrifft... ich konnte ihn überhaupt nicht zum Laufen bringen.

Irgendwelche Ideen/Alternativen?

7voto

Washu Punkte 817

Dies macht viele falsche Annahmen, die dich in den Hintern beißen werden.

Zunächst einmal ist die über Reflektion zurückgegebene Struktur in keiner Weise garantiert, auf Laufzeitstrukturen überhaupt zu verweisen. Daher ist es einfach falsch, zu versuchen, die enthaltenen oder zurückgegebenen Zeiger zu ändern.

Zweitens, wenn Sie etwas wie das Einfügen von Vor- / Nachmethodenaufrufinvarianten (als Beispiel) wünschen, sollten Sie wahrscheinlich Laufzeit-Proxobjekte konstruieren und diese statt dessen einfügen. Oder verwenden Sie die dynamische Methodenkonstruktion über den Emit-Namespace. Der Versuch, Dinge durch undokumentiertes/unbekanntes Verhalten zu manipulieren (wie der obige Code) funktioniert einfach nicht.

Sie müssen auch erkennen, dass der JIT entscheidet, wann er ausgeführt wird. Manchmal führt es gegen eine gesamte Klasse aus, manchmal führt es nur gegen eine einzelne Methode aus. Ihr Code versucht nicht einmal festzustellen, ob die Methode bereits JIT verarbeitet wurde, und nimmt blindlings an, dass der zurückgegebene Funktionszeiger geändert werden kann.

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