基本的な Aspect 実装をしてみた
結局、RealProxy 経由する限り、オブジェクトが MarshalByRefObject になるのは避けれないし、Attribute 実装で new をフックするにも、ContextBoundObject でないと、Attribute インスタンスでフックできない。
とはいえ、これはこれで使ったほうが早いかと思ったので、簡易ライブラリ化してみた。
http://www.white-azalea.net/index.php/p/azaleaworks/downloads/
これの機能追加だけでもしばらく楽しそうね。ということで、以下に使い方。
namespace TestAspect { class Program { static void Main(string[] args) { SampleTarget target = new SampleTarget(); target.Hello("Azalea"); } } }
お次に、SampleTarget
namespace TestAspect { [AzaleaWorks.Aspect.Aspect(typeof(TestLogger))] class SampleTarget : ContextBoundObject { internal void Hello(string p) { Console.WriteLine("Message : {0}!", p); } } }
最後に TestLogger の実装。
namespace TestAspect { class TestLogger : AzaleaWorks.Aspect.ProxyBase { public override IMessage InvokeMethod(IMethodCallMessage iMethodCallMessage) { Console.WriteLine("Called method : {0}", iMethodCallMessage.MethodName); IMessage result = base.InvokeMethod(iMethodCallMessage); Console.WriteLine("Exit method : {0}", iMethodCallMessage.MethodName); return result; } } }
InvokeConstructor メソッドも用意してあります。
適当に ProxyBase 継承したクラス作って、AspectAttribute に登録するだけ。
お察しの通り、インスタンス生成は Attribute でやってるから、引数なしのコンストラクタのみ対応。当然 Reflection でインスタンス生成してるし、キャッシュしてないから、インスタンスの大量生成をすると遅くなるかもね。
まずはインスタンスキャッシュと登録機構かなぁ?Aspect 用インスタンスを自前で作ってキャッシュする。で、使いまわす。既存のとは使い勝手違うから、別実装で用意かなぁ、、、、。
this ポインタ使うと補足できない、、、、RealProxy の限界かなぁ、、、、。
DynamicProxy 型だと事前にインターフェースを作って実装という制限が入るし、どうしたものか。