IDisposableを実装する場合のベストプラクティスは何ですか?
クラスに管理対象オブジェクトが1つある場合、それを実装するのに最適な経験則ですか、それともオブジェクトがクラスで作成されたのか、単に渡されただけなのかによって異なりますか?管理対象オブジェクトがまったくないクラスに対してもそれを行う必要がありますか?
nmanagedオブジェクトを意味する場合は、はい、クラスで処理している1つ以上のアンマネージリソースがある場合は常にそれを実装する必要があります。また、IDisposable自体である可能性のあるオブジェクトを保持している場合はパターンを使用し、クラスが破棄されるときにそれらを必ず破棄する必要があります。
(この質問は、印刷された場合にインクが不足する小さなプリンターを実行するのに十分な回数、すでに尋ねられていることに同意しました...)
誰もが(管理されていない)リソースについて言及していますが、追加することがもう1つあります。それは、クラスがスコープ外に出てガベージコレクションされるのを防ぐイベントハンドラーのフックアップを排除する必要がある場合に使用します。
例として、子ビューに挿入されるサービスがあります。その子ビューは、サービス上のさまざまな非同期終了タイプのイベントをサブスクライブします。その子ビューの所有者は、具体的なタイプが何であるかを知らず、単にインターフェースとしてそれを持っています。このサービスは、将来の任意の時点で範囲外になる可能性があり、GCされないままぶら下がってほしくない。その子ビューを削除すると、所有者はその子ビューでDisposeを呼び出して、イベントハンドラーのフックを解除する機会を与えます。これは少し工夫された(そして非常に疑似的なコード)例です。子ビューのインターフェースがIDisposable
をどのように実装しているかに注意してください。
public class OwnerView {
public OwnerView() {
_childView = new ChildView(myServiceReference);
}
public void CloseChildView() {
if (childView != null) {
_childView.Close();
_childView.Dispose();
}
_childView = null;
}
private IChildView _childView;
}
public class ChildView : IChildView {
public ChildView(MyService serviceRef) {
_serviceRef = serviceRef;
_serviceRef.GetSettingsAsyncFinished += new EventHandler(someEventHandler);
}
public void IDisposable.Dispose() {
_serviceRef -= someEventHandler;
}
private MyService _serviceRef;
}
public interface IChildView : IDisposable {
void DoSomething();
... etc ...
}
これについては、SOに関する他の人からのはるかに信頼できるコメントがあります。たとえば、 イベントハンドラーはガベージコレクションの発生を停止しますか? および- イベント処理に匿名デリゲートを使用する場合のガベージコレクション 。この codeproject の記事もチェックしてみてください。
IDisposableは、使用が終了したときに解放するリソースがクラスに保持されている場合に実装する必要があります。
クラスにアンマネージオブジェクト、リソース、開いているファイル、またはデータベースオブジェクトが含まれている場合は、IDisposable
を実装する必要があります。
docs IDisposableが何に適しているかについてはかなり明確だと思います。
このインターフェースの主な用途は、管理されていないリソースを解放することです。ガベージコレクタは、管理対象オブジェクトが使用されなくなると、その対象オブジェクトに割り当てられたメモリを自動的に解放します。ただし、ガベージコレクションがいつ発生するかを予測することはできません。さらに、ガベージコレクターは、ウィンドウハンドル、開いているファイルやストリームなどの管理されていないリソースについての知識を持っていません。
例もあります。その例では、IDisposable
を実装するクラスにハンドルが含まれています。ハンドルは、使用しなくなったら解放する必要があります。これはDispose()
メソッドで行われます。したがって、そのクラスのユーザーは、それがIDisposable
を実装していることを確認し、クラスが不要になったときに明示的に破棄する必要があることを知っています(ハンドルを解放できるようにするため)。インスタンスが不要になった場合は、常にIDisosable
インスタンスでDispose()
を呼び出すことがベストプラクティス(つまりルール)です。
廃棄する必要のあるプロパティがある場合。