GCにはまる

ぬるり。: COM クライアント実装の道程 for TaskScheduler その番外編2 〜 COM オブジェクトと GC とファイナライザを参考に、Excelを操作するCOMオブジェクトのラッパーを書いたんだけど、見事にはまった。

using (IExcel excel = new Excel())
using (IWorkbook book = excel.Books.Open("hoge.xsl"))
using (IWorksheet sheet = book.Sheets[1])
{
    // sheetに対して操作を行う
}


こんな感じでCOMオブジェクトを扱うときの面倒なtry-finallyを不要にしたんだけど、なんか動きがおかしい。しかもほぼ100%再現はするんだけど、場所がばらばら。
デバッグモードで例外の発生時点で中断させてみると、呼び出し履歴がすごく浅い、と言うか、メインから辿れないことが判明。
ステップ実行してもなんか急に例外が発生するので、スレッド周りか?と思いつつも自分でスレッドなんて開始してないし、GUIじゃないし・・・
で、Disposeメソッドがデストラクタから呼び出されていることを思い出し、GCの可能性に思い当たった。
試しに、usingブロックの最初でGCを起動してみると、見事に再現。


excel.Booksとか、book.Sheetsとかで一時オブジェクトを生成してるのが悪かったみたい。
と言うことで、生成する側のオブジェクトに生成したオブジェクトを保持させておくことで解決。