[解決済み] C#のFinalize/Disposeメソッドの使用について
質問
C# 2008
私は、コードにおけるfinalizeとdisposeメソッドの使用について、まだ混乱しています。私の質問は以下の通りです。
-
アンマネージドリソースを廃棄するときだけファイナライザが必要なのは知っています。しかし、アンマネージドリソースを呼び出すマネージドリソースがある場合、やはりファイナライザを実装する必要があるのでしょうか?
-
しかし、アンマネージド・リソースを直接または間接的に使用しないクラスを開発した場合、そのクラスには
IDisposable
を使用して、そのクラスのクライアントが 'using statement' を使用できるようにする必要がありますか?あなたのクラスのクライアントがusing文を使えるようにするためだけに、IDisposableを実装することは可能でしょうか?
using(myClass objClass = new myClass()) { // Do stuff here }
-
Finalize/disposeの使い方を説明するために、以下のような簡単なコードを開発しました。
public class NoGateway : IDisposable { private WebClient wc = null; public NoGateway() { wc = new WebClient(); wc.DownloadStringCompleted += wc_DownloadStringCompleted; } // Start the Async call to find if NoGateway is true or false public void NoGatewayStatus() { // Start the Async's download // Do other work here wc.DownloadStringAsync(new Uri(www.xxxx.xxx)); } private void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) { // Do work here } // Dispose of the NoGateway object public void Dispose() { wc.DownloadStringCompleted -= wc_DownloadStringCompleted; wc.Dispose(); GC.SuppressFinalize(this); } }
ソースコードに関する質問です。
-
ここではファイナライザーを追加していませんが、通常、ファイナライザーはGCから呼ばれ、ファイナライザーはディスポを呼び出します。ファイナライザを付けていないので、いつDisposeメソッドを呼べばいいのでしょうか?それを呼び出す必要があるのは、クラスのクライアントでしょうか?
つまり、例の私のクラスはNoGatewayという名前で、クライアントはこのようにクラスを使用し、廃棄することができるのです。
using(NoGateway objNoGateway = new NoGateway()) { // Do stuff here }
実行が using ブロックの終わりに達したとき、Dispose メソッドは自動的に呼び出されるのでしょうか、それともクライアントが手動で dispose メソッドを呼び出さなければならないのでしょうか。 すなわち、次のようになります。
NoGateway objNoGateway = new NoGateway(); // Do stuff with object objNoGateway.Dispose(); // finished with it
-
を使用しています。
WebClient
クラスでNoGateway
クラスを作成します。なぜならWebClient
を実装しています。IDisposable
インターフェイスを使用する場合、これはWebClient
は間接的にアンマネージドリソースを使用しますか?これに従うための厳密なルールはありますか?クラスがアンマネージドリソースを使用していることを知るにはどうしたらよいでしょうか?
解決方法は?
推奨される IDisposable パターンは ここで . IDisposableを使用するクラスをプログラミングする場合、一般的に2つのパターンを使用する必要があります。
アンマネージド・リソースを使用しないシールド・クラスを実装する場合は、通常のインターフェイス実装と同様にDisposeメソッドを実装するだけです。
public sealed class A : IDisposable
{
public void Dispose()
{
// get rid of managed resources, call Dispose on member variables...
}
}
unsealedクラスを実装する場合は、このようにします。
public class B : IDisposable
{
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// get rid of managed resources
}
// get rid of unmanaged resources
}
// only if you use unmanaged resources directly in B
//~B()
//{
// Dispose(false);
//}
}
でファイナライザーを宣言していないことに注意してください。
B
ファイナライザーを実装するのは、実際にアンマネージドリソースを廃棄する場合だけにしてください。CLR はファイナライズ可能なオブジェクトとそうでないオブジェクトを区別して扱いますが、たとえ
SuppressFinalize
が呼び出されます。
つまり、ファイナライザを宣言する必要がない限りは宣言してはいけないのですが、クラスの継承者にフックを与えることで、あなたの
Dispose
を実装し、アンマネージドリソースを直接使用する場合は、ファイナライザを自分で実装します。
public class C : B
{
private IntPtr m_Handle;
protected override void Dispose(bool disposing)
{
if (disposing)
{
// get rid of managed resources
}
ReleaseHandle(m_Handle);
base.Dispose(disposing);
}
~C() {
Dispose(false);
}
}
アンマネージド・リソースを直接使用しない場合(
SafeHandle
と友人はカウントされません。彼らは独自のファイナライザを宣言しているからです)、後でファイナライザを抑制する場合でも、GCはファイナライザブルクラスを異なる方法で扱うので、ファイナライザを実装しないでください。また、たとえ
B
はファイナライザを持たないが、それでも
SuppressFinalize
を使用して、ファイナライザを実装しているサブクラスを正しく処理します。
クラスが IDisposable インターフェースを実装しているということは、そのクラスを使い終わったときに処分されるべき、管理されていないリソースがどこかにあるということを意味します。実際のリソースはクラス内にカプセル化されているので、明示的に削除する必要はありません。単に
Dispose()
で包むか
using(...) {}
は、管理されていないリソースが必要に応じて取り除かれることを確認します。
関連
-
[解決済み】"出力タイプがクラスライブラリのプロジェクトは直接起動できない"
-
解決済み] Critical error detected c0000374 - C++ dll returns pointer off allocated memory to C# [解決済み] Critical error detected c0000374 - C++ dll returns pointer off allocated memory to C#.
-
[解決済み】Sequence contains no matching element(シーケンスにマッチする要素がない
-
[解決済み】Visual Studio: 操作を完了できませんでした。パラメータが正しくありません
-
[解決済み】エラー「必要なフォーマルパラメータに対応する引数が与えられていない」を解決する?
-
[解決済み] IDisposable インターフェースの正しい使用法
-
[解決済み] リフレクションを使ってジェネリックメソッドを呼び出すにはどうしたらいいですか?
-
[解決済み】HttpClientとHttpClientHandlerはリクエストの間にディスポされなければならないのでしょうか?
-
[解決済み】DataSetとDataTableはDispose()すべきですか?
-
[解決済み] ガベージコレクタはIDisposable.Disposeを呼んでくれるのですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] メンバー '<メンバー名>' にインスタンス参照でアクセスできない
-
[解決済み】C#で四捨五入する方法
-
[解決済み】SmtpException: トランスポート接続からデータを読み取れません:net_io_connectionclosed
-
[解決済み】クロススレッド操作が有効でない。作成されたスレッド以外のスレッドからアクセスされたコントロール
-
[解決済み】ORA-01008: すべての変数がバインドされていません。これらはバインドされています。
-
[解決済み] UnityでOnCollisionEnterが呼ばれない
-
[解決済み] EntityTypeにキーが定義されていないエラー
-
[解決済み】IntPtrとは一体何なのか?
-
[解決済み】プロセスが実行されているかどうかを知るには?
-
[解決済み】ユーザー設定値を別のユーザー設定値で設定する