MixIn Interfaces Proxy(その3)
コメント欄だと書きにくいので、エントリとして書くことに。
# sugimotokazuya 『1つ問題がありました。Mixinによるプロキシだと実装クラスの型で受け取れない(キャストできない)という制限がありました。』
とのことだが、実装クラスの型でも受け取りたいのであれば、一番ベーシックな、第一パラメタがTypeであるDynamicAopProxyのコンストラクタを使えば良いと思うのだが、いかがだろう。
昨日、デモとして書いたプログラムのMainメソッドを、今日の話向けに書き直してみた。
static void Main(string args) { IMethodInterceptor interceptor = new TraceInterceptor(); IPointcut pointcut = new PointcutImpl(new string { ".*" }); IAspect aspects = new AspectImpl(interceptor, pointcut); DynamicAopProxy proxy1 = new DynamicAopProxy(typeof(TestImpl), new IAspect[] { aspects }); ITest1 itest1 = proxy1.Create() as ITest1; itest1.TestFunctionOne("Hello ITest1"); ITest2 itest2 = itest1 as ITest2; itest2.TestFunctionTwo("Hello", "ITest2"); ITest3 itest3 = itest1 as ITest3; itest3.TestFunctionThree("Hello", "ITest3", "yah!"); TestImpl itestimpl = itest1 as TestImpl; itestimpl.TestFunctionOne("Hello TestImpl"); itestimpl.TestFunctionTwo("Hello ", "TestImpl"); itestimpl.TestFunctionThree("Hello", "TestImpl", "yah!"); System.Environment.Exit(0); }
この例であれば、DynamicProxyで拡張した型から生成したオブジェクトはITest1、ITest2、ITest3、そしてTestImplと、全ての型にキャストが可能だ。
と、ここまで書いていて思い出したが、そもそもインタフェースのプロキシが欲しかったのは、DynamicProxyを利用したDynamicAopProxyクラスのプロキシの場合、AOPの対象メソッドはvirtual修飾されたものだけに制限される、というのを回避することだった。
であれば、この方法は使えない。試しに、TestImplクラスのメソッドからvirtual修飾を外すと上のサンプルの実行結果は
TestFunctionOne(Hello ITest1) TestFunctionTwo(Hello, ITest2) TestFunctionThree(Hello, ITest3, yah!) TestFunctionOne(Hello TestImpl) TestFunctionTwo(Hello , TestImpl) TestFunctionThree(Hello, TestImpl, yah!)
このようにインターセプタが織り込まれない。当たり前だが駄目だ。
ちなみに、DynamicProxyは、複数のインタフェースをパラメタにとるクラスプロキシを作ることもできるのだが
//インタフェースの配列を第一パラメタにとる、コンストラクタ内部 this.enhancedType = this.generator.ProxyBuilder.CreateClassProxy(this.target.GetType(), interfaces);
このように生成したプロキシはインタフェースのメソッドと、クラスのvirtual修飾されたメソッドがプロキシ上で重複してしまうのか、メソッドの実行で永久ループを起こし、StackOverflow例外を投げるので、使いものにならなかった。
そうなると、今のところ思いつくのはクラス用のプロキシと、インタフェースのプロキシを別々に作ること位だろうか。
static void Main(string args) { IMethodInterceptor interceptor = new TraceInterceptor(); IPointcut pointcut = new PointcutImpl(new string { ".*" }); IAspect aspects = new AspectImpl(interceptor, pointcut); DynamicAopProxy proxy_forInterfaces = new DynamicAopProxy( new Type { typeof(ITest1), typeof(ITest2), typeof(ITest3) }, new IAspect { aspects }, null, new TestImpl()); ITest1 itest1 = proxy_forInterfaces.Create() as ITest1; itest1.TestFunctionOne("Hello ITest1"); ITest2 itest2 = itest1 as ITest2; itest2.TestFunctionTwo("Hello", "ITest2"); ITest3 itest3 = itest1 as ITest3; itest3.TestFunctionThree("Hello", "ITest3", "yah!"); DynamicAopProxy proxy_forClass = new DynamicAopProxy(typeof(TestImpl), new IAspect[] { aspects }); TestImpl itestimpl = proxy_forClass.Create() as TestImpl; itestimpl.TestFunctionOne("Hello TestImpl"); itestimpl.TestFunctionTwo("Hello ", "TestImpl"); itestimpl.TestFunctionThree("Hello", "TestImpl", "yah!"); System.Environment.Exit(0); }
これならば要件は満たせるが、少々無駄だ。Mixinなプロキシを作ること自体はできるはずなので、時間を見てもう少し調べてみよう。