IL EmitによるAOP (3)
ProxyFactoryは元の型を拡張した別な型とその実装を生成すると書きましたが実際にどのような型が生成されているのでしょう。前回書いた方法で動的に生成された型を物理的なアセンブリとして出力できることが解ったので実際に出力されたアセンブリを.NET Reflectorで逆アセンブルしてみましょう。
まず以下のインタフェースとクラスを用意します。これはDynamic Proxy Creation Using C# Emitでダウンロードできるコードのテストアプリケーションで使用されていたものと同じものです。
public interface ITest { void TestFunctionOne(); Object TestFunctionTwo( Object a, Object b ); } public class TestImpl : ITest { public void TestFunctionOne() { Console.WriteLine( "In TestImpl.TestFunctionOne()" ); } public Object TestFunctionTwo( Object a, Object b ) { Console.WriteLine( "In TestImpl.TestFunctionTwo( Object a, Object b )" ); return null; } }
次はメソッド呼び出しをインターセプトするクラスを用意します。このクラスはIProxyInvocationHandlerインタフェースの実装クラスであることが必要です。同記事のサンプルでは全てのメソッド呼び出しでセキュリティチェックを行うことを想定したSecurityProxyクラスが用意されていますので詳細はそちらを参照してください。
以上用意できたらサンプルプロジェクトを実行してみます。
static void Main( string[] args ) { ITest test = (ITest)SecurityProxy.NewInstance( new TestImpl() ); test.TestFunctionOne(); test.TestFunctionTwo( new Object(), new Object() ); }
実行が終了するとプロジェクトの実行パスに(大抵は\bin\debug\)"ProxyAssembly.dll"という名前のアセンブリDLLが生成されるのでこれを.NET Reflectorに読込ませて逆コンパイルした結果をコピペした結果が以下です。
.NET Reflectorで逆コンパイルを行っている様子
- TestImplProxyクラス定義
public sealed class TestImplProxy : ITest { // Methods public TestImplProxy(IProxyInvocationHandler); public override void TestFunctionOne(); public override object TestFunctionTwo(object, object); // Fields private IProxyInvocationHandler handler; }
- TestImplProxyコンストラクタ
public TestImplProxy(IProxyInvocationHandler handler1) { this.handler = handler1; }
- TestImplProxy#TestFunctionOne()メソッド
public override void TestFunctionOne() { if (this.handler == null) { } this.handler.Invoke(this, MetaDataFactory.GetMethod("DynamicProxy.ITest", 0), new object[0]); }
- TestImplProxy#TestFunctionTwo()メソッド
public override object TestFunctionTwo(object obj2, object obj3) { if (this.handler == null) { return null; } object[] objArray1 = new object[2] { obj2, obj3 } ; return this.handler.Invoke(this, MetaDataFactory.GetMethod("DynamicProxy.ITest", 1), objArray1); }
IL EmitによるILの動的な出力はコードの可読性が著しく低い為にProxyFactoryが実際にどんな型を生成しているのかをすぐに読み解くことは困難ですが実際にアセンブリを出力してその内容を確認してみるとどのような構造で元々のベースになった型(この場合はTestImplクラス)の呼び出しをインターセプトしているかが簡単に解ると思います。
コード中のMetaDataFactoryというクラスはProxyFactoryが型をILに生成していく際に使った型情報をキャッシュするのに使用している単なる入れ物です。