処分するものが何もない状況で「使用」することは適切ですか?


9

C#では、usingステートメントを使用して、ガベージコレクターを待たずにリソースを確定的な方法で破棄します。たとえば、次の目的で使用できます。

  • SQLコマンドまたは接続を破棄します。

  • ストリームを閉じ、ファイルのように基礎となるソースを解放し、

  • 無料のGDI +要素、

これは、using処理するものが何もない場合にますます使用されていることに気付きましたが、呼び出し元usingが2つの個別のコマンドではなくブロックを書き込む方が便利な場合に使用します。

例:

  • Stack Overflowチームによって作成されたMiniProfilerはusingプロファイルするブロックを示すために使用します。

    using (profiler.Step("Name goes here"))
    {
        this.DoSomethingUseful(i - 1);
    }

    1つの代替アプローチは、2つのブロックを持つことです。

    var p = profiler.Start("Name goes here");
    this.DoSomethingUseful(i - 1);
    profiler.Stop(p);

    別のアプローチはアクションを使用することです:

    profiler.Step("Name goes here", () => this.DoSomethingUseful(i - 1));
  • ASP.NET MVCもusingフォームに選択されています。

    <% using (Html.BeginForm())
       { %>
           <label for="firstName">Name:</label>
           <%= Html.TextBox("name")%>
           <input type="submit" value="Save" />    
    <% } %>

そのような使用法は適切ですか?いくつかの欠点があるため、それを正当化する方法:

  • 初心者は本や言語仕様書で説明されている使い方に対応していないので失われるでしょう、

  • コードは表現力豊かでなければなりません。ここでは、表現力が低下します。適切な使用法はusing、背後にガベージコレクターを待たずに解放する必要があるストリーム、ネットワーク接続、データベースなどのリソースがあることを示すためです。


2
2つのステートメントを個別に作成するアプローチには、以下のような単純なリソース管理と同じ問題がありusingます。後者のステートメント(などprofiler.Stop(p))は、例外と制御フローに直面した場合の実行が保証されていません。

1
@delnan:これは、MiniProfilerが2番目のアプローチを回避した理由を説明しています。ただし、2番目のものは、作成および保守が困難であるため、すべての場合で回避する必要があります。
Arseni Mourzenko 2013年



回答:


7

あなたの最後の声明-「使用の適切な使用法は、背後に、ガベージコレクターを待たずに解放する必要があるストリーム、ネットワーク接続、データベースなどのリソースがあることを示すことです」という誤りがあり、その理由はIDisposableインターフェイスのドキュメントに記載されています:http : //msdn.microsoft.com/en-us/library/system.idisposable.aspx

このインターフェースの主な用途は、アンマネージリソースを解放することです。

したがって、クラスがアンマネージリソースを使用する場合、GCを実行するかどうかは関係ありません。アンマネージリソースはGCされないため、GCを使用しても何も起こりません(https:// stackoverflow。 com / questions / 3607213 / what-is-meant-by-managed-vs-unmanaged-resources-in-net)。

「使用」の目的はGCで待機して避けることではないので、それはそれらのアンマネージリソースの解放を強制するのです、クラスのインスタンスがスコープ外に出ると、それのファイナライズが呼び出される前に、。これは明らかな理由で重要です。アンマネージリソースは他のアンマネージリソースに依存している可能性があり、それらが間違った順序で破棄(またはファイナライズ)されると、悪いことが発生する可能性があります。

したがって、usingブロックでインスタンス化されているクラスがアンマネージリソースを使用している場合、答えはyesです-適切です。

IDisposableは、アンマネージリソースを解放するためだけのものであるとは限らないことに注意してください。これが主な目的であるということだけです。それはあり、クラスの著者は、彼らが特定の時間に起こって強制することをいくつかのアクションを持っている場合もあり、IDisposableをを実装すると発生することを得るための方法かもしれないが、それはエレガントなソリューションですか否かができることを何かでありますケースバイケースでのみ回答されます。

どちらを使用する場合でも、「using」の使用は、クラスがIDisposableを実装することを意味するため、コードの表現力に違反しません。実際、何が起こっているのかが非常に明確になります。


「このインターフェースの主な用途は、アンマネージリソースを解放することです。」Microsoftのドキュメントはその点でうんざりだと私は言う。たぶん、どのようにのことを、彼らは FCLでそれを使用しますが、アプリケーション開発者は、十年に近いため、物事の様々なためにそれを使用している-正当な理由のためのいくつかを、いくつかのそれほどよくない理由のために。しかし、彼らのドキュメントのチャンクを引用しても、OPの質問にはまったく答えません。
ジェシーC.スライサー2013年

1
私の2番目の最後のパラに注意してください- 主な目的が唯一の目的である必要はありません。IDisposableはどのような理由でも実装できます。また、IDisposableは、予想される動作と使用法のスタイルを備えた既知のインターフェイスを提供するため、インスタンスをスコープから外す前に、他に何かする必要があることがわかります。重要なのは、IDisposableを実装している場合は、使用が適切であることです。その他はすべてプリアンブルです。
Maximus Minimus 2013年

1
基本的に、目的はGCの待機を回避することではなく、ファイナライザーの待機を回避することです。しかし、違いはわかりません。ファイナライザはGCによって呼び出されます。
2013年

GCは非決定的な方法で動作します-いつ呼び出されるかわかりません。GCはファイナライザも呼び出すだけですが、それ自体は破棄しません。実際のリソース自体はGCの制御外にあります。(1)オブジェクトのスコープが適切であり、(2)既知の時点で破棄が発生することがわかっている-オブジェクトがusingブロックのスコープを出ると、アンマネージリソースが失われる(または-最悪の場合-渡される)それを破壊する他の何かに)。本当に、これは単なるつまらないものです。ドキュメントを読んでください。繰り返す必要はありません。
Maximus Minimus 2013年

8

の使用はusingDispose()メソッドの存在を意味します。他のプログラマーは、そのようなメソッドがオブジェクトに存在すると想定します。したがって、オブジェクトが使い捨てでない場合は、そのオブジェクトで使用usingしないでください。

コードの明快さは王様です。を省略するか、オブジェクトにusing実装IDisposableします。

MiniProfilerは、usingプロファイリングされるコードを「隔離」するメカニズムとして使用しているようです。これにはいくつかのメリットがあります。おそらく、MiniProfilerがDispose()タイマーを停止するように呼び出しているか、MiniProfilerオブジェクトがスコープ外になるとタイマーが停止します。

より一般的には、usingある種のファイナライズを自動的に行う必要があるときに呼び出します。のドキュメントでhtml.BeginFormは、メソッドをusingステートメントで使用する</form>と、usingブロックの最後に終了タグが表示されると記載されています。

それは必ずしもそれがまだ虐待ではないという意味ではありません。


4
これまでのところ明らかです。質問は、とき(もし全てで)それが実現するのが適切であるさIDisposable/ Dispose()記述されたセンスOPに処分するために何かを持っていないにも関わらず?

2
私はそれを明確にしたと思いました。そこではないことが適切である時間が。
Robert Harvey

1
私のポイントは、(それが適切かどうかに関係なく)まったく意味をなすDisposeためusingに必要とされることです。OPの例はすべて実装Disposeしていますね。そしてIIUC、問題は、これらのクラスがDisposeStop()MiniProfilerのような)他のメソッドではなくを使用することが正しいかどうかです。

1
ええ、でもそれは問題ではありません。問題は、そうすることが良い考えかどうかです。

2
@delnan:繰り返しますが、私はそれを明確にしたと思いました。コードの意図がより明確になれば、それは良い考えです。そうでない場合は、そうではありません。
Robert Harvey

1

usingエラーと例外に対して安全です。Dispose()プログラマーのミスに関係なく、確実に呼び出されます。例外のキャッチや処理には影響しませんがDispose()、例外がスローされると、メソッドはスタックを再帰的に実行されます。

実装さIDisposeれているが、完了時に破棄するものがないオブジェクト。せいぜい、将来的に彼らのデザインを証明しています。ソースコードをリファクタリングする必要がないように、将来、ソースコードを破棄する必要があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.