制御の逆転とIDisposable(後始末編)

制御の逆転とIDisposable (DIxAOPによる解決)の続き。

追記 : このままではちょっとしたまずいことが発生する。それに関してはまた別なエントリで。

含みを持たせた終わり方だったのだが、ここで書いたちょっとしたまずいこととは、IDisposableなオブジェクトのDisposeが実行されないことだ。
はあ? そもそもIDisposable且つSingletonなオブジェクトを、DIコンテナから提供する場合に、不意にDisposeを呼ばれることをnoopやthrowで無効にしたかったのは、ぬしではなかったか? ああその通り。
最終的にアプリケーションは終了し、DIコンテナも破棄すべき時になったら、今度は散々無視してきたDisposeを実行してやらないとまずい。アンマネジリソースを含んだオブジェクトが対象だった時は相当まずいことになる。

早速対策を、といってもさほど難しくは無い。インターセプタ実装クラスのInvokeメソッドで使用するパラメタ型IMethodInvocationインタフェースはプロキシでは無い、元のオブジェクトの参照を保持しているからだ。
またもやSeasar2風のコードで恐縮だが、前回書いたNoopInterceptorを修正する例を。

public class NoopInterceptor : AbstractInterceptor
{
    private Stack disposableStack = new Stack();

    public NoopInterceptor()
        :base()
    {
        System.Windows.Forms.Application.ApplicationExit +=
            new EventHandler(
                delegate(object sender, EventArgs e) 
                {
                    foreach (IDisposable disposable in this.disposableStack)
                    {
                        disposable.Dispose();
                    }
                });
    }
    public override object Invoke(IMethodInvocation invocation)
    {
        IDisposable disposable = invocation.Target as IDisposable;
        if (disposable != null)
        {
            this.disposableStack.Push(disposable);
        }
        return null;
    }
}

最終的にIDisposable.Dispose()を実行するタイミングはいろいろ考えられるが、元々はWindowsFormsが対象なので、アプリケーション終了時でよいだろう。ということでApplicationExitイベントで、過去に呼ばれたであろう、Dispose()を実行することにした。
noopされた(Dispose)メソッドの対象がネストすることを考えて、格納先をスタックにしてみたが、今回のケースでは特定の型にアスペクトを適用するのが解っているので、あまり意味が無いのかもしれない。

まだ他に問題や改良点があるのかもしれないが、今はこれしか思いつかなかった。期待に沿わなかったとしたら申し訳ない。