web-dev-qa-db-ja.com

C#で "using"ブロックを使用する必要があるのはいつですか?

「使用」ブロックを使用する必要がある(またはすべきではない)特定のインスタンスはありますか。

using(SomeType t = new SomeType()){
    ...
}
69
Mark Carpenter

SomeTypeクラスが IDisposable を実装する場合。

90
Otávio Décio

一部のオブジェクトでは、作業が完了したときに何らかのアクションを実行する必要があります。通常、これは、オブジェクトが破棄する必要のある種類のリソースを使用するためです。たとえば、Fileクラスのファイルオブジェクトがあり、このオブジェクトがファイルシステムからファイルを開く場合、ファイルシステム内のファイルを再度閉じる必要があります。

ファイルオブジェクトをそのままにして、file.Close()の呼び出しを忘れた場合、ガベージコレクター(GC)が実行され、ファイルオブジェクトを使用していないものがなくなるまでクリーンアップされません。ガベージコレクターを実行するタイミングは、共通言語ランタイム(CLR)に任せて決定する必要があります。ファイルの処理を終えた後、GCがしばらく実行されない場合、ファイルが長時間開いたままになる可能性があります。これは、多くのファイルオブジェクトがある場合、または何かがファイルを開きたい場合に大きな問題を引き起こす可能性がありますが、残したファイルオブジェクトがまだぶらぶらしているためにできません。

この問題を解決するために、C#にはIDisposableインターフェイスがあります。これには、Disposeという1つのメソッドがあります。何らかのクリーンアップを必要とするクラスは、このDisposeメソッドを実装します。これにより、リソースを使用するオブジェクトをクリーンアップする標準的な方法が提供されます。 Disposeを呼び出す必要があるクラスがたくさんあります。これの問題は、コードがDisposeの呼び出しで覆われることであり、オブジェクトを新規作成してDisposeを呼び出してクリーンアップする場所が異なるため、従うのが難しいということです。そのため、コードをよく見て、Disposeの呼び出しが適切な場所にあるかどうかを確認する必要がありました。

この問題を解決するために、C#では「using」キーワードが導入されました。オブジェクトを新規に作成する場所に「using」キーワードを配置すると、Disposeが確実に呼び出されます。 usingステートメントの本体内に例外がスローされた場合でも、Disposeが発生したときに呼び出されることが保証されます。

そのため、リソースを割り当てるオブジェクトが確実にクリーンアップされるようにする場合は、「using」を使用する必要があります。


usingは、スタック、つまり関数で宣言されたオブジェクトにのみ使用できます。クラスのメンバーとして宣言されているオブジェクトに対しては機能しません。彼らのために、あなたは自分自身を破棄する必要があります。クラスにDisposeを実装して、必要なメンバーオブジェクトでDisposeを呼び出せるようにする必要があります。


使用する必要がある一般的なオブジェクトは、ファイル、データベース接続、ペンやブラシなどのグラフィックスオブジェクトです。


2つの操作を一緒に実行する場合にも使用されることがあります。たとえば、コードブロックが入力され、終了するときにログステートメントを記述したい場合、次のように使用できるログクラスを記述できます。

using( Log log = new Log("Doing stuff") )
{
    // Stuff
}

ログクラスのコンストラクタを作成してメッセージを書き出すことができ、Disposeメソッドもメッセージを書き出すことができます。ファイナライザ(〜Log)を実装して、Disposeメソッドが呼び出されない場合にアサートして、「使用」が「新しいログ」の周りに記憶されるようにします。

90
Scott Langham

タイプが using を実装する場合は常に IDisposable を使用します。ただし、 try/catch ブロック、とにかく(好みに応じて) finally ブロックを使用することもできます。

13
bdukes

shouldusingステートメントがある場合、他の多くの回答が表示されます。 notusingステートメントが必要な場合に特に対処する必要があります。

現在の関数のスコープ外でオブジェクトを使用する必要がある場合は、usingブロックを使用しないでください。良い例は、データベース接続を返すファクトリメソッド、またはデータリーダーを返す必要があるメソッドです。いずれの場合でも、usingステートメントを使用してオブジェクトを作成すると、メソッドが返される前に破棄されるため、メソッドの外部で使用できません。

さて、あなたはまだsureそれらのオブジェクトが破棄されることを望んでいるので、どこかにusingステートメントが必要かもしれません。オブジェクトが実際に作成されるメソッドには含めないでください。代わりに、usingステートメントで関数呼び出し自体をラップできます。

12
Joel Coehoorn

SomeTypeがIDisposableを実装する場合。

これは、SomeTypeがクリーンアップする必要がある管理されていないリソースを使用しているという開発者への手がかりです。

4
mbeckish

例:

        using(SqlConnection MyConnection = new SqlConnection("Connection string"))
        {
            MyConnection.Open();

            //...

            // 1. SQLConnection is a type that implements IDisposable
            // 2. So you can use MyConnection in a using statement
            // 3. When using block finishes, it calls Dispose method of 
            // SqlConnection class
            // 4. In this case, it will probably close the connection to 
            // the database and dispose MyConnection object

        }

IDisposableを実装する独自のオブジェクトを作成できます。

public class MyOwnObjectThatImplementsIDisposable : IDisposable
{

    //... some code

    public void Dispose()
    {
        // Put here the code you want to be executed when the
        // using statement finish.
    }
}

したがって、usingステートメントでMyOwnObjectThanImplementsIDisposable型のオブジェクトを使用できます。

        using(MyOwnObjectThatImplementsIDisposable MyObject = new MyOwnObjectThatImplementsIDisposable)
        {

            // When the statement finishes, it calls the 
            // code you´ve writed in Dispose method
            // of MyOwnObjectThatImplementsIDisposable class
        }

お役に立てれば

4
Javier

このコンテキストでは、usingステートメントはIDisposableを実装する型に便利です。コードブロックがusingステートメントのスコープを終了すると、Dispose()が暗黙的に呼び出されます。使用後すぐに廃棄するオブジェクトを操作する場合は、良い習慣です。

2
Dave Swersky

usingブロックの使用に注意する必要がある特定のインスタンスは、とWCFサービスクライアントです。

このMSDN記事 で述べたように、IDisposableブロックでWCFクライアント(usingを実装する)をラップすると、クライアントが残されるエラーをマスクできます。障害状態(タイムアウトや通信の問題など)。要するに、Dispose()が呼び出されると、クライアントのClose()メソッドが起動しますが、フォールト状態にあるためスローおよびエラーになります。元の例外は、2番目の例外によってマスクされます。良くない。

MSDNの記事自体を含む、さまざまな回避策があります。その他は IServiceOriented および blog.davidbarret.net にあります。

私は最後の方法、私自身を好みます。

2
Eric King

サマリールールが必要な場合。 IDisposableを使用するオブジェクトがキャッチされない場合は、必ずusingを使用します。基本的に、このパターンを使用しています:

try
{
  //instantiate and use object
}
finally
{
  //dispose object
}

キャッチが不要な場合は、を使用すると入力を節約できます。これは良いことです。

2

「使用する」lo C#言語を追加する根本的な理由は次のとおりです。GCがIDisposableを呼び出すのを待つのは理にかなっていないリソースもあります。たとえば、DB接続。 try/catch/finallyを使用する場合、接続がぶら下がることはありませんが、GCが作動しなくなるまで接続はハングしたままになります(明示的に閉じない場合)。 "using"(しゃれを許す)を使用する場合、閉じるのを忘れた場合や、usingブロック内で何らかの例外が発生した場合でも、すぐに接続を解放します。
別の理由は、以前の投稿が言及したように、プログラマが最終的にクリーンアップするために常に使用するとは限らないことです。例外の場合に最終的に使用しないと、リソースのリークが発生します…

1
Dan

主なルールは次のとおりです。*オブジェクトがIDisposableインターフェイスを実装する場合は、USINGステートメントを使用します。

このインターフェイスは、オブジェクトのリソースを解放するDisposeメソッドを提供します。このメソッドが呼び出されない場合、CLRがガベージコレクションを実行したい限り、オブジェクトはメモリ内にとどまります。プログラマーがUSINGステートメントを使用すると、最後にオブジェクトが破棄され、すべてのリソースが解放されます。

使用されなくなったすべてのリソースをできるだけ早く解放することが非常に重要です。

詳細については、次のリンクを参照してください。 Microsoft

1
rpf

また、何かがIDisposeを実装している場合、また、データベース接続やファイルハンドルなどの非管理リソースを保持したい場合は、using()ステートメントを使用することも追加します。

Tが名前とアドレスを保持するCustomerオブジェクトのようなList<T>などの通常のオブジェクトである場合、必要はありません。ガベージコレクターは、これを管理するのに十分スマートです。ただし、ガベージコレクターは、接続プールに接続を返したり、ファイルハンドルを閉じたりしません。

0
Chris

1つの状況は、コードブロックの先頭で何かを行い、ブロックの最後で無条件に(スローがあっても)元に戻す場合です。

構築する(およびusing内で呼び出す)使い捨てクラスのctorがアクションを実行し、Disposeメソッドがそのアクションを取り消します。これは通常、私が使用する方法です。

0
Allen Rice

他の人々はすでに「IDisposable」について言及しています。

ただし、「using」ステートメントを使用する場合の注意点の1つは、「using」内でスローされた例外は、「SomeType」が関係なく破棄されると見なされてもキャッチされないことです。

そのため、次のスニペットでは、

_using (SomeType t = new SomeType()){
    throw new Exception("thrown within using");
}
_

throw new Exception("thrown within using");は無視しないでください。

0
Sung M. Kim