22

最近、次のように記述されたコードを見ました。

public void Dipose()
{
   using(_myDisposableField) { }
}

これは私にはかなり奇妙に思えます。myDisposableField.Dispose();

明示的に呼び出しを行うよりも、「使用」を使用してオブジェクトを破棄する理由は何ですか?

4

4 に答える 4

24

いいえ、まったくありません。空にコンパイルされて、try/finallyを呼び出すことになりDisposeます。

それを除く。コードをより速く、より読みやすく、そしておそらく最も重要なことに(以下を読み続けるにつれて)その意図をより表現力豊かにするでしょう。

更新:それらは少し賢く、同等のコードにはnullチェックが必要であり、Jon Skeetのアドバイスに従って、マルチスレッドが含まれる場合はローカルコピーも取得します(null間の競合を回避するための標準のイベント呼び出しパターンと同じ方法で)チェックとメソッド呼び出し)。

IDisposable tmp = _myDisposableField; 

if (tmp != null) 
    tmp.Dispose();

私が書いたサンプルアプリのILで見ることができることから、あなたも直接_myDisposableFieldとして扱う必要があるようです。IDisposableこれは、いずれかのタイプがIDisposableインターフェイスを明示的に実装し、同時にメソッドを提供する場合に重要になります。public void Dispose()

try-finallyこのコードも、を使用するときに存在するものを複製しようとはしませんusingが、これは不要であると見なされると想定されています。ただし、Michael Graczykがコメントで指摘しているように、オファーの使用は、例外、特に(いつでも発生する可能性がある)finally例外に対する保護を提供します。ThreadAbortExceptionとはいえ、これが実際に発生するウィンドウは非常に小さいです。

しかし、私は彼らがこれを行ったという事実に5人を賭けて、それが彼らに与える微妙な「利益」を本当に理解していませんでした。

于 2012-08-02T13:48:10.113 に答える
2

あなたが投稿した例には、非常に微妙ですが邪悪なバグがあります。

次のように「コンパイル」されます。

try {}
finally
{
    if (_myDisposableField != null) 
        ((IDisposable)_myDisposableField).Dispose();
}

オブジェクトは、外側ではなく、using 句内でインスタンス化する必要があります。

リソース オブジェクトをインスタンス化してから、変数を using ステートメントに渡すことができますが、これはベスト プラクティスではありません。この場合、制御が using ブロックを離れた後、オブジェクトはスコープ内にとどまりますが、おそらくそのアンマネージ リソースにはアクセスできません。つまり、完全に初期化されていません。using ブロックの外側でオブジェクトを使用しようとすると、例外がスローされる危険があります。このため、using ステートメントでオブジェクトをインスタンス化し、そのスコープを using ブロックに限定することをお勧めします。

—<a href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement" rel="nofollow noreferrer">using ステートメント (C# リファレンス)

言い換えれば、それはダーティでハッキーです。

クリーン バージョンは、MSDN で非常に明確に綴られています。

  • インスタンスの使用をメソッドに制限できる場合はusing、境界にコンストラクター呼び出しがあるブロックを使用します。Dispose直接使用しないでください。
  • 親が破棄されるまでインスタンスを存続させる必要がある (しかし本当に必要な) 場合は、 Disposable パターンのみを使用して明示的に破棄します。Dispose カスケードを実装するにはさまざまな方法がありますが、非常に微妙で見つけにくいバグを避けるために、すべて同じように行う必要があります。MSDN のFramework Design Guidelinesには非常に優れたリソースがあります。

最後に、管理されていないリソースIDisposableを使用する場合にのみパターンを使用する必要があることに注意してください。それが本当に必要であることを確認してください:-)

于 2012-10-15T22:24:39.173 に答える
-2

using ステートメントは、参照されたオブジェクトを破棄する必要があるコードのスパンを定義します。

はい、一度 .dispose を呼び出すことはできますが、オブジェクトのスコープが何であるかはあまり明確ではありません (IMHO)。YMMV。

于 2012-08-02T13:51:44.073 に答える