MixIn Interfaces Proxy

Seasar.DynamicProxyで2回インターセプターが実行される

Interfaceを実装している場合は、Interface毎にProxyを作成していたのですが、Interface毎のProxyを作るときに既に拡張されたクラスからProxyを作ろうとしていたためです。DynamicAopProxyAspectWeaverの問題ですね。

複数のインタフェースがMixinされたプロキシを作るのが目的なのであれば、DynamicProxyの機能が使えると思う。Castle.DynamicProxyのProxyGeneratorのCreateメソッドのバリエーションを利用して、

Type[] interfaces = 対象となる全てのインタフェースのMixin(配列)
ProxyGenerator generator = new ProxyGenerator();
generator.CreateInterfaceProxy(interfaces, targetObject.GetType();

こんな風に、一発でMixinのプロキシが生成できますので、DynamicAopProxyクラスには、これに対応したインタフェースプロキシ専用のコンストラクタを用意して、

public DynamicAopProxy(Type interfaces, IAspect aspects, Hashtable parameters, object target)
{
    this.target = target;
    if (this.target == null) this.target = new object();
    this.type = target.GetType();
    this.aspects = aspects;
    this.parameters = parameters;
    this.generator = new ProxyGenerator();
    this.enhancedType = this.generator.ProxyBuilder.CreateInterfaceProxy(interfaces, this.target.GetType());
    isInterfaceProxy = true;
    this.SetUpAspects();
}

これでを呼び出せば、一発で対象のインタフェース全てをMixinしたプロキシの型が生成できるのではないだろうか。このように拡張した型は、コンストラクタのパラメタが一つ多くなるので、プロキシインスタンスの生成では、

public object Create()
{
    ArrayList args = new ArrayList();
    args.Add(this);
    if (this.isInterfaceProxy && this.target != null)
    {
        args.Add(this.target.GetType());
    }
    return Activator.CreateInstance(this.enhancedType, args.ToArray());
}

などと、ベタだがコンストラクタでセットしたisInterfaceProxyフィールドを判定して、コンストラクタの引数に、ターゲットの型をセットする必要がある。

と、こんな感じでできないだろうか。

公開したソースコードに関しては既に修正済み。
Seasar.Framework.Aop.DynamicProxy.DynamicAopProxy.cs
※自前のソースとの違いを出来るだけ減らしたいので、今回より.NET Framework 2.0専用としました。