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になってるのもそのためです。


で、次はメソッドの生成になります。