14

try/catch/finaly内部にブロックがあるメソッドがあります。tryブロック内で、次のように宣言SqlDataReaderします。

SqlDataReader aReader = null;          
aReader = aCommand.ExecuteReader();

finallyブロック内で手動で破棄されるオブジェクトは、クラスレベルで設定されたオブジェクトです。IDisposableそれで、上記のように実装するメソッド内のオブジェクトは、SqlDataReader自動的に破棄されますか?whileループが実行された後、リーダーのコンテンツを取得するためにClose()呼び出されます(これは、呼び出しと同じである必要があります)。の呼び出しがない場合、メソッドが終了するか、オブジェクトがスコープ外になると、このオブジェクトは自動的に閉じられますか?aReaderDispose()Close()Close()

編集:私はusing声明を知っていますが、私を混乱させるシナリオがあります。

4

6 に答える 6

27

いいえ、オブジェクトがスコープ外になったときにオブジェクトが自動的に破棄されることはありません。

IDisposable多くのオブジェクトは、最終的に確実に廃棄されるように「フォールバック」ファイナライザーを実装していますが、ガベージコレクションされた場合に廃棄される保証はありません。

IDisposableできればブロックで包むことにより、オブジェクトが確実に廃棄されるようにする責任がありusingます。

于 2009-12-02T13:46:21.637 に答える
8

ブロックを使用しusing {...}てIDisposableオブジェクトをラップする必要があります-Dispose()メソッド(SqlDataReaderの場合はClose()メソッドに渡されます)は、usingブロックが終了したときに呼び出されます。を使用しない場合using、オブジェクトがスコープ外になったときにオブジェクトが自動的に破棄されることはありません。オブジェクトが存在する場合は、ガベージコレクション時にリソースを削除するのはオブジェクトファイナライザー次第です。

using (SqlDataReader aReader = aCommand.ExecuteReader())
{
    // ... do stuff
}   // aReader.Dispose() called here
于 2009-12-02T13:43:16.697 に答える
2

上記のすべてに同意します。必ずDispose()自分自身を呼び出す必要があります。これを行う最も簡単な方法は、usingステートメントを使用することです(これは、finallyブロック内で自分で行うこともできます。これはより冗長ですが、必要な場合もあります)。これを行わないと、アプリケーションがハンドルなどのアンマネージリソース、さらにはアンマネージメモリをリークしていることがわかります。特に、このすべての下のどこかで一部のCOMコンポーネントが使用されている場合、またはWin32APIが呼び出されている場合はそうです。これは明らかに、パフォーマンスと安定性の問題、および過度のリソース使用につながる可能性があります。

実装するオブジェクトが、メソッドをIDisposable呼び出してDispose(bool disposing)アンマネージリソースを解放するファイナライザーを実装する必要があるという理由だけで、これが発生する保証はありません。したがって、絶対にそれに依存するべきではありません。この点の詳細については、たとえば、http://msdn.microsoft.com/en-us/library/b1yfkh5e%28VS.71%29.aspxを参照してください。

また、他に覚えておくべきことは、タイプに使い捨てのメンバーがある場合、タイプは実装する必要があるということですIDisposable(これらのメンバーのライフサイクルが別のタイプによって管理されている場合を除き、明らかに厄介になる可能性があります)。このようなメンバーを1つのメソッドで使用するか、特定の機能を実装するには、それらを使用するメソッドでローカル変数/パラメーターにすることを検討する必要があります。

于 2009-12-02T13:57:38.720 に答える
1

Disposeパターンは、どのオブジェクトが他のどのオブジェクトに対してDisposeを呼び出すかについては保証しません。時々起こるかもしれませんが、気にしないでください。代わりに、すべてのIDisposableオブジェクトに対してDispose()が呼び出されていることを確認するのはユーザーの責任です。そのための最良の方法は、usingステートメントを使用することです。例えば:

using (SqlDataReader aReader = aCommand.ExecuteReader())
{
    // your code
}
于 2009-12-02T13:44:22.593 に答える
0

「finallyブロックでは、手動で破棄されるオブジェクトは、クラスレベルで設定されたオブジェクトです」というステートメントに戸惑います。クラスレベルで設定されたオブジェクトとは、フィールドを意味しますか?フィールドの存続期間は予測できず、たまたま呼び出したメソッドに依存するため、通常のメソッド内でこれらを破棄するべきではありません。IDisposableを実装し、Disposeメソッドでフィールドを破棄することをお勧めします。

于 2009-12-02T13:51:22.740 に答える
-2

Usingステートメントは役に立ちますか

于 2009-12-02T13:44:20.193 に答える