質問

次の些細なコードを検討してください。

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 Delegateにデバッグコードを挿入することです。これは同等です。

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

ひねりは、私がこれを行うことができなければならないということです ランタイム, 、そのため、コンパイル時間と後処理方法は問題外です。

私の最初のアプローチは、Delegate.comBine()を使用して、ProgueおよびEpilogueメソッドをFoo Delegateに追加しました。悲しいかな、これは値を返すために機能しません。

私の現在のアイデアは、System.Reflection.EmitとDynamicMethodを潜在的なソリューションとして使用することです。私が知る限り、私はfooimplementationのためにMethodInfoを取得し、その方法を取得し、それを動的なメートルに変換し、私の試行ブロックをそこに注入する必要があります。

残念ながら、私はこれを行う方法が全くわかりません。手を貸してもよい人はいますか?それとも、別の(できればよりシンプルな)アイデアはありますか?

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

役に立ちましたか?

解決 6

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

他のヒント

式を使用できます。

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

これにより、ランタイムでプロローグとエピローグの表現を構築できます。

あなたがやろうとしていることを確認してください、しかしそれが単にリダイレクトされている場合 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");
    }
}

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

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

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

それともMono.cecilさえ?http://www.mono-project.com/cecil

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

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

試してみることもできます 刻み CodePlexでコードを管理したコード(C#またはVB.NET)に挿入して簡単に。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top