8

タイトルは多かれ少なかれそれをすべて言います。この記事に基づいて、私はこれを思いついた:

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

これは実際に機能します...時々-.-

たとえば、これは機能します。

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

    public static void B()
    {
        Console.WriteLine("Bai World");
    }
}

ただし、これはそうではありません(SEHException)。関数を定義する順序を変更するだけでした。

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

    public static void A()
    {
        Console.WriteLine("Hai World");
    }
}

記事のコードに関しては...私はそれをまったく動作させることができませんでした。

アイデア/代替案はありますか?

4

1 に答える 1

7

これはお尻にあなたを噛むだろう多くの悪い仮定をしています。

まず最初に、リフレクションを介して返される構造は、ランタイム構造を指すことがまったく保証されていません。そのため、含まれている、または返されるポインタを変更しようとするのは、まったく間違っています。

次に、(例として)pre / postメソッド呼び出しの不変条件を挿入するようなことをしたい場合は、おそらくランタイムプロキシオブジェクトを作成し、代わりにそれらを挿入する必要があります。または、Emit名前空間を介して動的メソッド構築を使用します。文書化されていない/未知の動作(上記のコードなど)を介して物事を操作しようとしても、うまくいきません。

また、JITがいつ実行されるかを決定することを理解する必要があります。クラス全体に対して実行される場合もあれば、単一のメソッドに対してのみ実行される場合もあります。コードは、メソッドがまだJITされているかどうかを判断しようとはせず、返された関数ポインターが変更可能であると盲目的に想定します。

于 2011-01-29T22:20:05.500 に答える