DirectSoundのマネージラッパーを書いています。(これは、私の特定の問題を解決する単純な部分ラッパーであり、それ以上のものではありません。NAudioなどについては教えてください。)IDirectSound8をラップするマネージドクラスはIDisposableである必要があり、その理由は何ですか。IDirectSoundBuffer8についての同じ質問。
1 に答える
技術的には:はい。実際には:いいえ。IDirectSound8はCOMインターフェイスであり、相互運用ライブラリを備えた.NETで非常に便利にラップされています。RCW。そのRCWは、基盤となるCOMコクラスオブジェクトの参照カウントを管理します。RCWは、管理されていないリソースに非常に依存しているにもかかわらず、IDisposableを実装していません。
そうでない理由は、IDisposableを正しく実装することがほとんど不可能だからです。COMコクラスは複数のインターフェースを実装し、1つを作成すると参照カウントに追加されます。破棄が安全になる前に、これらのインターフェイスポインタがすべて使用されていないことを100%確認する必要があります。これを行うのは非常に困難です。これらのポインターは予期しない方法で作成されます。いずれかのインターフェイスのインデックス付きプロパティを使用する場合と同様に、中間インターフェイスポインタがコードに表示されることはありません。
これは実際の問題ではありません。ガベージコレクターが参照カウントを処理し、ファイナライザーが作業を完了します。オブジェクトが解放されるまでに少し時間がかかるだけです。標準のGCの動作。残念ながら、アウトプロセスCOMサーバーには目に見える副作用があり、コードがインターフェイスの使用を停止した瞬間にプロセスがTaskMgrプロセスリストから消えない場合、プログラマーはイライラする傾向があります。ここやフォーラムでは、多くの「Excel/Wordが終了しない」という質問があります。
とにかく実装したい場合は、Dispose()実装でMarshal.FinalReleaseComObject()を呼び出すことで実装できます。失敗のリスクが大幅に高まることに注意してください。その呼び出しを間違えると、失敗を診断するのが非常に困難になります。ネイティブコードでオブジェクトを削除し、それへのポインタを保持しているのとまったく同じです。それが実際に即座に解放されなければならない「重い」オブジェクトである場合、GC.Collect()+ GC.WaitForPendingFinalizers()は、それを間違えるリスクをはるかに少なくして、仕事をやり遂げます。もちろん副作用もあります。