そもそも必ずしも Marshal.ReleaseComObject を呼び出すべきではないというお話もあるようです。またまとめます。
COM の呼び出し
TaskScheduler taskScheduler = null;
try
{
taskScheduler = new TaskScheduler.TaskScheduler();
ITaskFolder folder = null;
try
{
folder = taskScheduler.GetFolder("");
// 何かする
}
finally
{
Marshal.ReleaseComObject(folder);
}
}
finally
{
Marshal.ReleaseComObject(taskScheduler);
}
吐き気がする……吐き気がしない?
ぼくがかんがえたさいきょうのかいけつさく
public static class ComObject
{
public static void Using<T>(T obj, Action<T> action)
{
try
{
action(obj);
}
finally
{
// Marshal.IsComObject による判定はメソッドの先頭でおこない例外をスローするのもアリかも
if (!ReferenceEquals(obj, null) && Marshal.IsComObject(obj))
{
Marshal.ReleaseComObject(obj);
}
}
}
}
こういうのを作っておいて、こうじゃ!
ComObject.Using(new TaskScheduler.TaskScheduler(), taskScheduler =>
{
taskScheduler.Connect(null, null, null, null);
ComObject.Using(taskScheduler.GetFolder(""), folder =>
{
// 何かする
});
});
……もう少しなんかいい感じにならないかなぁ。
(参考) 検討したけどボツにした案
using (var taskScheduler = ComObject.Create(new TaskScheduler.TaskScheduler()))
{
taskScheduler.Value.Connect(null, null, null, null);
using (var folder = ComObject.Create(taskScheduler.Value.GetFolder("")))
{
// 何かする
});
});
.Value がウザい……けど、素直っちゃ素直。
ComObject の生成をコンストラクタじゃなくてファクトリメソッドにしているのは型引数に対して型推論を効かせたいからです。Tuple.Create と一緒ですね。
ネストを防げる妙案!
はぇ~氏からこんな提案を頂きました。
@chocolamint こんな感じとか? https://gist.github.com/sayurin/ee9b87ab8786489a438a 結局のところ、.NETのオブジェクト参照とCOMのオブジェクト参照が一致しないから、GCで回収したくても未使用か判定できないとか、そういう。— はぇ~ (@haxe) August 27 ,2015