DynamicProxy実験2
DynamicProxyの実験として、自分でもDynamicProxyを実装してみます(・∀・)
とりあえず、指定したinterfaceを実装して、Interceptorとtargetをメンバフィールドに持つTypeの生成について、コンストラクタの生成あたりまでについてです。
生成されるTypeについては、C#で書くとこんなカンジになるものを想定します。
public class IMyInterface_Proxy : IMyInterface { private IInterceptor __interceptor; private object __target; public IMyInterface_Proxy(IInterceptor interceptor, object target) { this.__interceptor = interceptor; this.__target = target; } ... }
__targetの型は、targetがnullの場合はobject、それ以外はtarget.GetType()にしています。
IMyInterfaceのメソッドについては、__interceptorのInvoke()を呼び出すようなコードを後で生成します。
で、コードはこんな感じになります。
private Type CreateType(Type[] interfaceTypes, IInterceptor interceptor, object target, string typeName) { Type type = null; Type objType = typeof( System.Object ); Type interceptorType = typeof( IInterceptor ); Type taegetType = ( ( target != null ) ? target.GetType() : typeof( System.Object ) ); AssemblyName assemblyName = new AssemblyName(); assemblyName.Name = ASSEMBLY_NAME; assemblyName.Version = new Version( 1, 0, 0, 0 ); AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly( assemblyName, AssemblyBuilderAccess.RunAndSave ); ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule( MODULE_NAME, MODULE_FILE_NAME ); TypeAttributes typeAttributes = TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed; TypeBuilder typeBuilder = moduleBuilder.DefineType( typeName, typeAttributes, objType, interfaceTypes ); FieldBuilder interceptorField = typeBuilder.DefineField( INTERCEPTOR_FILED_NAME, interceptorType, FieldAttributes.Private ); FieldBuilder targetField = typeBuilder.DefineField( TARGET_FILED_NAME, taegetType, FieldAttributes.Private ); ConstructorInfo superConstructor = objType.GetConstructor( new Type [ 0 ] ); ConstructorBuilder proxyConstractor = typeBuilder.DefineConstructor( MethodAttributes.Public, CallingConventions.Standard, new Type[] { interceptorType, taegetType } ); ILGenerator ilGenerator = proxyConstractor.GetILGenerator(); ilGenerator.Emit( OpCodes.Ldarg_0 ); ilGenerator.Emit( OpCodes.Call, superConstructor ); ilGenerator.Emit( OpCodes.Ldarg_0 ); ilGenerator.Emit( OpCodes.Ldarg_1 ); ilGenerator.Emit( OpCodes.Stfld, interceptorField ); ilGenerator.Emit( OpCodes.Ldarg_0 ); ilGenerator.Emit( OpCodes.Ldarg_2 ); ilGenerator.Emit( OpCodes.Stfld, targetField ); ilGenerator.Emit( OpCodes.Ret ); foreach( Type interfaceType in interfaceTypes ) { GenerateMethod( interfaceType, typeBuilder, interceptorField, targetField ); } return( typeBuilder.CreateType() ); }
コンストラクタのコードはILをゴリゴリして生成しています(´・ω・`)
で、この出力はこんな風になります。
IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: ldarg.0 IL_0007: ldarg.1 IL_0008: stfld class [Proxy]Proxy.IInterceptor Proxy.IMyInterface_Proxy::__interceptor IL_000d: ldarg.0 IL_000e: ldarg.2 IL_000f: stfld object Proxy.IMyInterface_Proxy::__target IL_0014: ret
ILが間違っていても実行するまでわからないので、AssemblyBuilder.Save()でファイルに保存して、ILDasmでチェックしながら進めるという地味なデバッグをしてました(´ω`)
AssemblyBuilderを定義する際の引数がAssemblyBuilderAccess.RunAndSaveになってるのもそのためです。
で、次はメソッドの生成になります。