特定のクラスに対してトレース機能、つまり、すべてのメソッド呼び出し (メソッド シグネチャと実際のパラメータ値) とすべてのメソッド終了 (メソッド シグネチャのみ) をログに記録したいと考えています。
以下のことを前提として、これをどのように実現すればよいでしょうか。
- C#用のサードパーティのAOPライブラリは使いたくないので、
- トレースしたいすべてのメソッドに重複したコードを追加したくないので、
- クラスのパブリック API を変更するつもりはありません。クラスのユーザーは、すべてのメソッドをまったく同じ方法で呼び出すことができる必要があります。
質問をより具体的にするために、3 つのクラスがあると仮定しましょう。
public class Caller
{
public static void Call()
{
Traced traced = new Traced();
traced.Method1();
traced.Method2();
}
}
public class Traced
{
public void Method1(String name, Int32 value) { }
public void Method2(Object object) { }
}
public class Logger
{
public static void LogStart(MethodInfo method, Object[] parameterValues);
public static void LogEnd(MethodInfo method);
}
呼び出すにはどうすればいいですかロガー.LogStartそしてロガー.ログ終了あらゆる電話に対して方法1そして方法2変更せずに発信者.通話メソッドと明示的に呼び出しを追加することなくトレース方法1そしてトレース方法2?
編集: Call メソッドを少し変更できる場合の解決策は何でしょうか?
ベストアンサー1
C# は AOP 指向の言語ではありません。C# にはいくつかの AOP 機能があり、他の機能をエミュレートすることもできますが、C# で AOP を作成するのは困難です。
あなたがやりたいことを正確に実現する方法を探しましたが、簡単な方法は見つかりませんでした。
私の理解では、あなたがやりたいことはこれです:
[Log()]
public void Method1(String name, Int32 value);
それを実現するには主に2つの選択肢があります
MarshalByRefObject または ContextBoundObject からクラスを継承し、IMessageSink から継承する属性を定義します。この記事良い例があります。それでも、MarshalByRefObject を使用するとパフォーマンスがひどく低下することを考慮する必要があります。つまり、10 倍のパフォーマンス低下について話しているのですから、試す前によく考えてください。
もう 1 つのオプションは、コードを直接挿入することです。実行時には、リフレクションを使用してすべてのクラスを「読み取り」、その属性を取得して適切な呼び出しを挿入する必要があります (また、Reflection.Emit メソッドは使用できないと思います。Reflection.Emit では、既存のメソッド内に新しいコードを挿入できないと思うからです)。設計時には、CLR コンパイラの拡張機能を作成することになりますが、その方法については正直まったくわかりません。
最後の選択肢は、IoCフレームワークほとんどの IoC フレームワークはメソッドをフックできるエントリ ポイントを定義することによって機能するため、これは完璧なソリューションではないかもしれませんが、達成したい内容によっては、妥当な近似値になるかもしれません。