6

次の些細なコードを考えてみましょう。

using System;   
class Test
{
    delegate int FooDelegate(int i);
    FooDelegate Foo = FooImplementation;
    static int FooImplementation(int i)
    {
        return i + 1;
    }

    public static void Main()
    {
         Foo(1);
    }
}

私がやりたいのは、Fooデリゲートにデバッグコードを挿入することです。これは次のようになります。

FooDelegate Foo = delegate(int i)
{
    try
    {
        DebugPrologue();
        return FooImplementation(i);
    }
    finally
    {
        DebugEpilogue();
    }
};

ツイストは、実行時にこれを実行できる必要があるため、コンパイル時と後処理の方法は問題外です。

私の最初のアプローチでは、Delegate.Combine()を使用して、プロローグメソッドとエピローグメソッドをFooデリゲートに追加しました。残念ながら、これは戻り値を変更するため機能しません。

私の現在のアイデアは、潜在的なソリューションとしてSystem.Reflection.EmitとDynamicMethodを使用することです。私が知る限り、FooImplementationのMethodInfoを取得し、そのMethodBodyを取得し、それをDynamicMethodに変換して、try-finallyブロックをそれに挿入する必要があります。

残念ながら、これを行う方法がまったくわかりません。手を貸してくれる人はいますか?または、別の(できればもっと単純な)アイデアがありますか?

編集:ここでのユースケースは、OpenGLバインディング(http://www.opentk.com)のデバッグです。パラメータが大きく異なる2226メソッドを注入する必要があるため、一般的なアプローチが必要です。

4

6 に答える 6

3

式を使用できます。

var param = Expression.Parameter(typeof(int), "i");

Foo = Expression.Lambda(
         Expression.TryFinally(
            Expression.Block(
               <expression for DebugPrologue>,
               Expression.Invoke(<expression for FooImplementation>, param)),
            <expression for DebugEpilogue>),
         param)
      .Compile();

このようにして、実行時にプロローグとエピローグの式を作成できます。

于 2010-12-05T00:16:45.490 に答える
0

Postsharpのようなものを使用することを検討しましたか? http://www.sharpcrafters.com/postsharp

またはエンタープライズライブラリポリシーインジェクション? http://msdn.microsoft.com/en-us/library/ff650672.aspx

またはMono.Cecil? http://www.mono-project.com/Cecil

于 2010-12-04T22:26:23.083 に答える
0

何をしようとしているのかを確認してください。ただしFooImplementation、フィールドでポイントされているものを単にリダイレクトする場合は、次のFooようにすることができます。

class Test
{
    delegate int FooDelegate(int i);
    static FooDelegate Foo = FooImplementation;

    static int FooImplementation(int i)
    {
        return i + 1;
    }

    public static void Main()
    {
        Inject();
        Foo(1);
    }


    public static void Inject()
    {
        var oldImpl = Foo;

        Foo = i =>
            {
                try
                {
                    BeginDebug();
                    return oldImpl(i);
                }
                finally
                {
                    EndDebug();
                }
            };
    }

    public static void BeginDebug()
    {
        Console.WriteLine("Begin Foo");
    }

    public static void EndDebug()
    {
        Console.WriteLine("End Foo");
    }
}

もちろん、Injectは同じクラスである必要はありませんが、フィールド/プロパティに公的にアクセスできない場合は、Reflectionを使用してそれを行う必要がありますが、それでもそれほど難しくはありません。

于 2010-12-04T21:54:30.867 に答える
0

TypeMockは、問題に対する実行可能な解決策かもしれません: http ://www.typemock.com/

RealProxyクラス(http://msdn.microsoft.com/en-us/library/system.runtime.remoting.proxies.realproxy.aspx)を使用して、実行時に挿入されたコードを最初に呼び出す独自のプロキシを生成することもできます。次に、実際のメソッドを呼び出します。

于 2010-12-04T22:36:36.417 に答える
0

また、 codeplexでCInjectを試して、マネージコード(C#またはVB.NET)にコードを非常に簡単に挿入することもできます。

于 2012-09-03T05:12:41.287 に答える
0

最終的に私がやったことは、Mono.Cecilを使用して独自の書き換えソリューションを実装することでした。シンプルで高速で、問題なく動作します。残念ながら、これはビルド後のイベントとして実行する必要があるため、これは実際にはランタイムコードインジェクションではありません。

于 2013-12-24T15:46:13.050 に答える