2009-07-30 4 views
12

あなたが持っているときのようなコード:Disposeはいつ必要ですか?

Bitmap bmp = new Bitmap (100, 100); 
Graphics g = Graphics.FromImage (bmp); 

Pen p = new Pen (Color.FromArgb (128, Color.Blue), 1); 
Brush b = new SolidBrush (Color.FromArgb (128, Color.Blue)); 

g.FillEllipse (b, 0, 0, 99, 99);  
g.FillRegion (b, pictureBox1.Region); 

pictureBox1.BackColor = Color.Transparent; 
pictureBox1.Image = bmp; 

あなたはペンを配置し、ブラシする必要がありますか? bmpとgについてはどうですか?

私の主な質問は、これらを手作業で処理する場合、スコープから出てすぐに処分されないのはなぜですか?あなたが手動でそれらを処分しなかった場合、それは起こりますか?人々がこれを手作業で行うことが遅れですか?

答えて

1

はい、bmp、g、b、pはすべてIDisposableであるため、すべてをDispose()する必要があります。好ましくはusing() {}ブロックを使用することによって。

例外があります。を使用する場合、p2を廃棄しないでください。これは在庫品と呼ばれています。 Brushes.Blackなどでも同じです。

については、は、すべての使い捨てクラスで同じです。 .Netは参照カウントを使用しないので、参照が有効範囲外になったときに即時アクションができません(できません)。

ガベージコレクタに残しておくと、最終的に解放されますが、(非常に)非効率的です。すぐに処理しないため、Graphicハンドルが不足しているのに失敗したASP.NET(!)アプリケーションがわかっています。それは画像を生成していた。

+0

ありがとうHenk。 Pens.BlueでDisposeに電話するとどうなりますか?それは悪いですか? –

+1

あなたは知っている、私は本当に知りません。私は試してみる前に推測を取る:あなたはすぐに例外を取得するか、何も起こらない。 –

+1

私は試みました:あなたは、変更が許可されていないというメッセージと共にSystem.ArgumentExceptionを取得します。 –

1

Disposeは、アンマネージドリソースを廃棄するために使用されます。

したがって、私はIDisposableオブジェクトのインスタンス化をusingステートメントにラップするので、ペンが管理していないリソースについて心配する必要はありません。

17

はい、ペンとブラシだけでなく、BitmapGraphicsも処分する必要があります。

変数自体がオブジェクトではなく参照であり、C#コンパイラは所有権が依然としてそれらの参照に属しているかどうかわからないため、スコープから外れても処分されません(例:FillEllipse言語コンパイラにはライブラリのセマンティクスに関する特別な知識はないことを覚えておいてください)。

using (Bitmap bmp = new Bitmap (100, 100)) 
using (Graphics g = Graphics.FromImage (bmp)) 
using (Pen p = new Pen (Color.FromArgb (128, Color.Blue), 1)) 
using (Brush b = new SolidBrush (Color.FromArgb (128, Color.Blue))) 
{ 
    g.FillEllipse (b, 0, 0, 99, 99);  
    g.FillRegion (b, pictureBox1.Region); 
} 

このコンパイラインサートは、すべてのオブジェクトを一度に配置されていることを確認して、必要に応じて自動的にDisposeに呼び出しを行います:あなたは所有権がその範囲に制限されていることを示したい場合は

は、あなたがusingステートメントを使用します対応するusingスコープが残されます(通常、returnまたはbreakのようなコントロール転送によって、または例外として)。

C++のバックグラウンドをご存知の方は、const std::auto_ptrに似ていますが、ここでは言語構造で、クラスフィールドでは使用できません。

+1

本当ですか?面白い。以前はGraphicsオブジェクト以外は何も見たことがありませんでした。これについて詳しく語るMSサイトはありますか? – derGral

+4

'Dispose'を呼び出すか、' using'ステートメントを使うべきですが、もしそうでなければ、ある種のAPIがそれを使用しているかもしれないので、 'Pen'がスコープから外されないのは当然ではありません。 'Pen'はファイナライザを持っています。これは到達不能になった後、何らかの不特定の時間に実行されます(短命オブジェクトの場合、すぐ後になる可能性があります)。そうなると、' Dispose'に相当します。 –

+1

参照:http://msdn.microsoft.com/en-us/library/system.drawing.pen.dispose.aspx - "call Dispose ...それ以外の場合、使用しているリソースは、ガベージコレクタPenオブジェクトのFinalizeメソッドを呼び出します。 –

3

C#は、スコープの外に出るとすぐに物を「破壊」したり破棄したりしません。

これらのクラスは、最も可能性が高いは自動的に彼らがスコープの外に行くの後に不確定な時にガベージコレクションされているときに呼び出されます彼らの特別なFinalizer方法、中にしがみつくアンマネージリソースを解放します。

しかし、それに依存することは、あなたのコントロールから外れているものに依存することであり、しばらくの間は起こらないかもしれません。

クラスがIDisposableを実装している場合は、Dispose()を手動で呼び出すか、usingブロックにラップすることをお勧めします。そうすれば、次のことを確認できます。

A.アンマネージドリソースは、確実に解放されます。 です。

B.管理対象外のリソースは、できるだけ早く解放されます。

6

私は他の人がここでのコード例を入れている知っているが、私はそう始め、私は終了します:

using (Bitmap bmp = new Bitmap(100, 100)) 
{ 
    using (Graphics g = Graphics.FromImage(bmp)) 
    { 
    using (Pen p = new Pen(Color.FromArgb(128, Color.Blue), 1)) 
    { 
     using (Brush b = new SolidBrush(Color.FromArgb(128, Color.Blue))) 
     { 
     g.FillEllipse(b, 0, 0, 99, 99); 
     g.FillRegion(b, pictureBox1.Region); 

     pictureBox1.BackColor = Color.Transparent; 
     pictureBox1.Image = bmp; 
     } 
    } 
    } 
} 

それがあっても、自動的にオブジェクトにDispose()を呼び出すので、私はいつも私のコードでusingを使用usingブロックで例外が発生しています。私はのSharePointプロジェクトでそれをたくさん使っています(しかしそれは別の話です...)。

+3

正しいですが、Pavelsサンプルのように、複数の使用を1つのブレースペアに折り畳むことが慣例になっています。 –

+1

クール、以前はその技術を見ていませんでした。今からそれを使うつもりだと思っています:) –

+0

私は[質問](http://stackoverflow.com/q/14946381/799558)に、ビットマップを ' pictureBox1.Image'と私の答えはあなたのものとまったく同じでした(私はすでに私の答えを削除しました)。彼らは画像の画像も処分されると私に言った。この状況で ''使用することはできますか? – AbZy

2

使い捨てパターンが正しく使用されている場合、Disposeであり、厳密には必要ありません。 - オブジェクトが完成したときに呼び出されるので、リソースなどが漏れません。

しかし、使い捨て物は通常は限られたネイティブリソースを直接制御することが多いので、Disposeに連絡するとよいでしょう。オブジェクトは通常すぐにファイナライズ/収集されるわけではないので、オブジェクトをもう使用しないと、それらのリソースはちょうどぶら下がり、無駄になります。廃棄するとすぐにリソースが解放され、プログラムの他の部分(または場合によっては他のプログラム)で使用できるようになります。

ブロックが完了したら、ブロックusingが自動的にオブジェクトを破棄します。そのため、ブロック内にDisposeが表示されることはめったにありません。

ショートバージョン:(例:それはPens.Blue、またはGraphicsなどのシステムオブジェクトではありません場合は、OnPaintなどに渡される)オブジェクトがIDisposableを実装し、あなたのコードがそれを作成した場合、あなたは完全にしているとき、それが配置されるべきDisposeを呼び出すか、またはDisposeCloseが一般的です)を呼び出すために指定された他のメソッドを呼び出すか、usingブロックを使用して呼び出します。 にはがありませんが、ほとんどの場合それを処理する必要があります。

+1

放棄されたオブジェクトの多くは、自分自身をクリーンアップしません。いくつかのケースではクリーンアップはかなりシンプルですが、他のクリーンアップは本質的に不可能です。特定のクラスのオブジェクトを放棄することが安全であることを知っていない限り、最初にDisposeを呼び出さずにオブジェクトを放棄すると、悪いことが起こることが想定されます。 – supercat

+0

IDisposableを正しく実装しているオブジェクトはすべて、*放棄された場合に自身をクリーンアップします。 BCLのすべてのディスポーザブルと同様です。ほとんどの場合、ファイナライザを見つけて解雇する必要がないオブジェクトはほとんどありません。ほとんどの場合、ファイナライザで「Dispose」を呼び出すことができます。ネイティブリソースを使いこなす人は、彼らが適切に解放されないと何が起こるのかをよく知っている。ネイティブリソースを直接使いこなしていない人は、本当にIDisposableを実装する必要はありません。 – cHao

+0

コンストラクタがINotifyPropertyChangedオブジェクトを受け入れ、そのオブジェクトが(ChangeCounter)が作成されてからPropertyChangedイベントが発生した回数を報告するクラスChangeCounterを構築したいとします。そのようなクラスは、放棄された場合、それ自体後にクリーンアップすることができますか? INotifyPropertyChangedは、PropertyChanged.RemoveHandlerの実装がファイナライザスレッドから安全に使用できることを保証していません。 – supercat