標準の Begin/End パターンを使用してメソッドを公開BeginLongOperation()
し、 を実装するクラスがあるとします。EndLongOperation()
IDisposable
Dispose()
への呼び出しと への呼び出しの間の呼び出しBeginLongOperation()
を処理するのは私のクラスの責任EndLongOperation()
ですか?
もしそうなら、これを行う適切な方法は何ですか?
BeginLongOperation() と EndLongOperation() への呼び出しの間の Dispose() への呼び出しを処理するのは私のクラスの責任ですか?
いいえ、適切に破棄するのはクラスの呼び出し元の責任です。これはメソッドで行うことができますEndLongOperation
。メソッドはすぐに戻るusing
ため、ステートメントでインスタンスをラップすることはできません。BeginLongOperation
の例WebClient
:
var client = new WebClient();
client.DownloadStringCompleted += (sender, e) =>
{
try
{
if (e.Error == null)
{
Console.WriteLine(e.Result);
}
}
finally
{
((WebClient)sender).Dispose();
}
};
client.DownloadStringAsync(new Uri("http://www.google.com"));
Begin/End メソッドは非同期であると想定しています。または、オブジェクトを別のスレッドから操作できること。
まず、クラスのインスタンスを破棄する必要があるかどうかを判断する必要があります。その場合、Dispose() メソッド (クラスはIDisposableインターフェイスを実装する必要があります) を設計して、実行される長い操作を妨げないようにする必要があります。実装するポリシーによって異なります。長い操作が完了するのを待ちますか、それとも Dispose() メソッドの呼び出しで長い操作を中断する必要がありますか?
通常、クラスの内部コードから Dispose() メソッドを呼び出すことはありませんが、実際には Dispose() 呼び出しを不適切な使用から保護する必要があります。
したがって、可能性のあるシナリオからコードを保護するのはあなたの責任だと思います。Begin と End の間の (望ましくない) 呼び出しに対してさえもです。
LATER EDIT:もちろん、ここにいる他の人があなたに言ったように、あなたのクラスのユーザーの責任はそれを適切に使用することですが、私はこれに依存しません. ご存知のように、オブジェクトへの最後の参照がなくなると、オブジェクトはガベージ コレクションの対象になります。この不適切な使用パターンは、非非同期/シングル スレッド設計であっても、実際に Start/End 間の Dispose() の呼び出しを決定する可能性があります。
IDisposable の背後にあるアイデアを以下に示します。それはあなたの質問にも答えていると思います。
このインターフェイスの主な用途は、管理されていないリソースを解放することです。ガベージ コレクターは、管理対象オブジェクトが使用されなくなると、そのオブジェクトに割り当てられたメモリを自動的に解放します。ただし、ガベージ コレクションがいつ発生するかを予測することはできません。さらに、ガベージ コレクターは、ウィンドウ ハンドルや開いているファイルやストリームなどのアンマネージ リソースを認識しません。
このインターフェイスの Dispose メソッドを使用して、ガベージ コレクターと共にアンマネージ リソースを明示的に解放します。オブジェクトの消費者は、オブジェクトが不要になったときにこのメソッドを呼び出すことができます。
したがって、クラスを使用して Dispose() を呼び出す開発者の義務です。
このようなクラスのオブジェクトを using ブロック内で宣言するのではなく、手動で破棄してください。
このオブジェクトを使用するクラスの EndLongOperation ハンドラ内で、そのようなクラスの dispose を呼び出すことができます。