DynamicMethodを使用したランタイムコードインジェクション?
-
08-10-2019 - |
質問
次の些細なコードを検討してください。
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)に挿入して簡単に。