IDisposable を確実に成敗する

わんくま同盟東京勉強会#64(2012/10/22)と名古屋勉強会#19(2011/10/29) での発表資料です。
数カ所から欲しいと言われていた資料ですが、長いこと放置していて申し訳ありません。
# #18 の LT 資料があがってるのを見て勘違いしていたorz

発表資料
ソースコード

DB やファイルアクセスをするクラスは、一般に IDisposable インターフェースを継承して作成します。
こうすると using ステートメントを使用できるようになり、アンマネージドリソースを確実に解放できるようになります。

using ステートメントは非常に優れたシンタックスシュガーなんですが、欠点もいくつかあります。
たとえば親が子供を産み、子供が孫を産み……で、その一族がことごとく IDisposable なオブジェクトだった場合はネストがえらいことになります。
LDAP だったら 3 段程度、Excel を操作しようとすると 6 段 7 段当たり前の世界が待っています。
もちろんフラットな書き方をすればネスト問題の多くは解決するんですが、たとえばExcelのブックを開く場合のように、子供を産む前に何らかの処理が必要になる場合はネストが深くなってしまいます。
他にもスコープが一つのメソッド内に限られるなど、運用の柔軟性に欠ける面もあります。

ところが Stack を使用すると、これらの問題が一気に解決してしまいます。
IDisposable オブジェクトを生成するたびに StackK に積み込み、解放のタイミングで foreach で回して、それぞれの Disopse() メソッドを呼び出すわけです。
通常は try-finally の finally 節で上記の解放処理をしますが、メンバ変数の場合は Dispose() メソッドやデストラクタで行ってもいいでしょう。

しかし、タイプ量が増えるのが問題です。
そこで Stack をメンバに持つ Disposer クラスを設計しました。
Disposer.Push() で IDisposable オブジェクトを自身のスタックに積み込みますが、このメソッドは引数をそのまま返すため、スマートポインタのように扱うことが可能です。
さらに IDisposable を継承しているため、using ステートメントを使用することで解放処理がさらに簡便になります。

さらに発展させて、Disoposer をメンバに持つ、Excel の各クラスのラッパークラスを作ってみましょう。
レイトバインドで Excel を叩こうと思うと、どのみちラッパークラスが必要です。
そして、それぞれが子供を産むたびに自身の Disposer に積み込むようにしましょう。
すると従来の COM アクセスでは不可能だった「プロパティの連鎖」すら可能になってしまいます。

レイトバインドの場合、インストールされている Excel のバージョンを問いません。
この機構は元々 Excel2000/2003 両対応のアプリケーションを作成するのに作ったんですが、そのアプリは2007, 2010 に至る現在でもノーメンテナンスで動作しています。
# 32bit/64bit 両対応でもあるから、改修予算を取りっぱぐれたというorz