制御の逆転とIDisposable(後始末編)
制御の逆転とIDisposable (DIxAOPによる解決)の続き。
追記 : このままではちょっとしたまずいことが発生する。それに関してはまた別なエントリで。
含みを持たせた終わり方だったのだが、ここで書いたちょっとしたまずいこととは、IDisposableなオブジェクトのDisposeが実行されないことだ。
はあ? そもそもIDisposable且つSingletonなオブジェクトを、DIコンテナから提供する場合に、不意にDisposeを呼ばれることをnoopやthrowで無効にしたかったのは、ぬしではなかったか? ああその通り。
最終的にアプリケーションは終了し、DIコンテナも破棄すべき時になったら、今度は散々無視してきたDisposeを実行してやらないとまずい。アンマネジリソースを含んだオブジェクトが対象だった時は相当まずいことになる。
早速対策を、といってもさほど難しくは無い。インターセプタ実装クラスのInvokeメソッドで使用するパラメタ型IMethodInvocationインタフェースはプロキシでは無い、元のオブジェクトの参照を保持しているからだ。
またもやSeasar2風のコードで恐縮だが、前回書いたNoopInterceptorを修正する例を。
public class NoopInterceptor : AbstractInterceptor { private StackdisposableStack = 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)メソッドの対象がネストすることを考えて、格納先をスタックにしてみたが、今回のケースでは特定の型にアスペクトを適用するのが解っているので、あまり意味が無いのかもしれない。
まだ他に問題や改良点があるのかもしれないが、今はこれしか思いつかなかった。期待に沿わなかったとしたら申し訳ない。