3

私は読んで、C#のusingステートメントが何をするのか理解していると信じています(間違っている場合は修正してください):IDisposableオブジェクトを限られた範囲(usingブロック)への読み取り専用として初期化します。の前に初期化できることはわかっていますがusing、それによってスコープが制限されることはありませんが、ここでは推奨されません。

http://msdn.microsoft.com/en-us/library/yh598w02.aspx

私は、どのクラスがどのクラスのサブクラスであるかに常に注意を払っているわけではありません。どのクラスが IDisposable から継承されているかはよくわかりません。ステートメントでどのクラスを使用できるかだけでなく、同僚がブロックusingでどのクラスを見つけることを期待しているでしょうか? usingブロックにはどのクラスを含める必要がありusingますか? usingまた、ブロックを使用せず、Dispose を呼び出さないことに何か問題がありますか? それはメモリだけですか、それとも安定性ですか?

4

10 に答える 10

16

厳密に言えば、その関数を実装IDisposableし、スコープがその関数に限定されているオブジェクトは、usingブロック内にある必要があります。このIDisposableインターフェイスは、管理されていないリソース (データベース接続、ファイル ハンドル、ウィンドウ ハンドルなど) を処理するクラスが、これらのリソースをタイムリーで決定論的な方法で破棄できるようにするために存在します。

一般に、IDisposableオブジェクトがクラス内で使用される方法は 3 つあります。

  1. オブジェクトは、単一のメソッド呼び出しの範囲内で作成され、不要になります。これは非常に一般的であり、using使用できる (そして使用する必要がある) 場合です。
  2. オブジェクトはクラスによって作成され (またはクラスに渡され)、その有効期間は 1 回のメソッド呼び出しのスコープを超えますが、クラスの有効期間を超えません。たとえば、クラスが を作成しStream、オブジェクトの存続期間にわたってそれを使用する必要があるとします。この場合、クラスはそれ自体を実装し、独自のメソッドが呼び出されIDisposableたときに所有するオブジェクトを破棄する必要があります。Disposeこの例は次のようになりますSystem.IO.StreamWriter
  3. オブジェクトはクラスに渡されますが、クラスはそれを「所有」していません。これは、IDisposableオブジェクトの使用可能な有効期間が単一のメソッド呼び出しの範囲を超えており、オブジェクトの有効期間を超えている可能性があることを意味します。この場合、他の誰かが を呼び出す責任を負う必要がありますDispose

最初のケースは、遭遇する最も一般的なケースであり、usingブロックが存在する理由です。例外が発生した場合でも、オブジェクトが確実に破棄されるようにします。

いくつかの例:

  • ストリーム クラス
  • データベース接続/コマンド
  • コントロール

を実装するクラスの完全なリストはありませんIDisposable。そのリストはかなり大きく、遭遇することのないクラスでいっぱいになるからです。クラスが何をするか考えてみてください。閉じる必要のあるある種の接続またはファイルを開きますか? 一般に、解放する必要があるある種のリソースを取得しますか? もしそうなら、それはおそらくそれを実装します。基本的なレベルでは、コンパイラが で囲むことを許可する場合、コンパイラは をusing実装しIDisposableます。

を呼び出さないことの結果についてはDispose、考慮しないでください。Dispose を呼び出します。確かに、クラスが管理されていないリソースを直接使用する場合、オブジェクトが収集され、誰かがそれを呼び出せなかった場合に dispose を呼び出すファイナライザーを定義する必要がありますが、それは設計上の選択ではありません。これまで、私が知る限り。

于 2010-07-07T15:47:15.443 に答える
13

それは記憶についてではありません。これは、ファイルハンドル、データベース接続などの他のリソースに関するものです。

基本的に、クラスが実装IDisposableしている場合、それは、管理されていないリソースがあり、残しておくのに費用がかかる可能性があるため、完了したら破棄する必要があるというシグナルです。(たとえば、接続プールの接続が不足したり、ファイルハンドルが開いたままになり、別のコードが同じファイルを再度開くことができなくなったりする場合があります)。

于 2010-07-07T15:32:37.977 に答える
2

を実装するすべてのクラスを常に呼び出す必要があります。これは、ブロックを介して最も簡単に実行できます。DisposeIDisposableusing

これは記憶だけの問題ではありません。これは資源だけの問題でもありません。これは正しさについてです。

StreamWriterが有名な例です。マイクロソフトはプログラマがDispose. これはメモリやリソースだけではありません。このStreamWriter例では、書き込まれるファイルが切り詰められる可能性があります。

データベーストランザクションがロールバックされていた(実際には上司のコードで)厄介なバグを1回追跡する必要がありました...原因はDispose呼び出されていなかったため、コミットしようとしていたことが判明しましたプロセスが終了したときにディスクに大量に書き込まれます (プロセスの終了時にファイナライザーのタイムアウトがあります)。修正はほんの数usingブロックでした。

3 番目の例: Microsoft のマネージ ESENT ラッパー クラスには、正しい順序 (「外部」クラスが最後) で呼び出す必要 がある「3 層」廃棄スキームがあります。Dispose

したがって、 が適切に呼び出されない場合に誤った動作が発生する実例が 3 つあります。Dispose他のクラスも同様の動作を示す場合があります。

原則として、常に呼び出す必要がありますDispose

于 2010-07-07T15:46:05.173 に答える
1

usingブロックを使用せず、Disposeを呼び出さないことには、絶対に多くの間違いがあります。メモリやリソースがリークする可能性があります。使用は便利ですが、クラスがIDisposableから派生するオブジェクトでDisposeを呼び出す必要があります。

于 2010-07-07T15:32:46.277 に答える
1

どのクラスが破棄可能であるかについては、IntelliSense を自分で調べるか、経験から学ぶだけです。いくつかの一般的なものには、Imageとその子、実際にはほとんどのSystem.Drawing名前空間、多数のファイル ストリーム、データベース接続などが含まれます。

いつ呼び出されるかという限り - できるだけ早く。使い捨てであることがわかっていて、それで終わっていることがわかっている場合は、Dispose を呼び出します。

実装する .NET 基本クラスの多くはIDisposable破棄可能なパターンを実装していると思います。つまり、ガベージ コレクターがそれらを取得するようになったときに、適切に破棄されます。それでも、使い終わったら処分するべきです。

  1. 参照をぶら下げたままにしておくと(リーク)、破棄されないか、または
  2. しばらくの間、GC が回らない可能性があります。

さらに、自分で作成したクラスの場合、ガベージ コレクションは、アンマネージ リソースの適切な破棄と同じではありません。よくある混乱です。使い捨てパターンは自分で実装する必要があります。

于 2010-07-07T15:37:20.317 に答える
1

IDisposable の目的は、アンマネージ リソース (ファイル、データベース、グラフィックス コンテキストなど) と対話するオブジェクトが、自分自身をクリーンアップできるようにすることです。using ステートメントは、次の構文の便利な省略形です。

var disposable = new MemoryStream();
try
{
  //do some work with the disposable object
}
finally
{
  if (disposable!=null)
     disposable.Dispose();  
}

もちろん問題は、どのオブジェクトが IDisposable を実装しているかを知ることです...残念ながら、ドキュメント以外に自動的に知る方法はありません。using 以外で使用されている IDisposables をチェックする Fxcop 設定があると思いますが。

于 2010-07-07T15:54:16.890 に答える
1

少なくとも、管理されていないリソースを使用したすべてのクラス

于 2010-07-07T15:31:23.470 に答える
1

クラスが実装する主な理由は、IDisposable管理されていないリソースを解放することです。ガベージ コレクターは、マネージド リソースが範囲外になり適切と判断したときに解放しますが、非マネージド リソースについては認識していません。Dispose メソッドを呼び出すと、明示的にリソースが解放されます。

usingブロックを使用しないか、Disposeメソッドを呼び出さないと、メモリ リークの問題が発生し、安定性の問題が発生する可能性があります。

usingを実装するクラスを扱うときは、常にブロックを使用する必要がありますIDisposable。ただし、例外を処理できるように、ブロック内でTry.. Catch.. Finally確実に呼び出すことをお勧めします。Disposefinally

于 2010-07-07T15:42:24.140 に答える
0

ブロックの使用の下でどのクラスを使用するかについて心配する必要はありません。usingステートメントで使用したものがIDisposbaleを実装していない場合は、赤/青の波が表示されます。あなたがその欠如している使い捨てのインターフェースを知ることができるように。そして、私が使用した限り、ほとんどすべてのクラスのフレームワークにIdisposableが実装されています。ただし、カスタムクラスでは、実装する必要があります

于 2010-07-07T15:33:32.773 に答える
0

すぐに呼び出せるクラスusingは次のとおりです。

  • ストリーム
  • データベース接続、コマンド、およびデータ リーダー
  • リーダーとライター

Dispose する必要があるクラスは他にもたくさんありますが、上記のクラスは頻繁に使用され、使用範囲が狭いことがよくあります。

usingはい - を使用せず、呼び出さないことには問題がありますdispose。クラシックは、データベースへの接続を閉じない Web アプリであり、接続を開いたままにしておくと、データベース サーバーからリソースを効果的に吸い上げます。

于 2010-07-07T15:50:47.317 に答える