2

IDisposableから派生したクラスメンバー(myDisposableMem)を持つクラス(myClass)があるため、Dispose()メソッドがあります。ローカル変数の場合は、using(...){...}を使用して、このオブジェクトでDispose()が呼び出されるようにすることができます。しかし、それはクラスのメンバーです。Disposedがメンバーに呼び出されていることを確認する正しい方法は何ですか?私は2つの方法を考えることができます:

1)クラスにfinallize()を追加してから、内部でmyDisposableMem.Dispose()を呼び出します。

また

2)クラスをIDisposibleから継承させます。

public class myClass : IDisposable
{
 ...
  public void Dispose()
  {
    myDisposableMem.Dispose();
  }
}
void main ()
{
  using (myClass myObj = new MyClass())
  {
   .... 
  }
}

それとももっと良い方法がありますか?

4

3 に答える 3

2

オブジェクトまたはコードの一部は、参照を保持している場合に「所有」していると言われIDisposable、他のオブジェクトまたはコードの一部がそれを呼び出すと信じる理由はありませんDispose。ローカル変数に保持されているを所有するコードは、IDisposable通常、その変数を破棄する前に、その変数を呼び出すか、Dispose所有権を受け取ることを期待する他のコードまたはオブジェクトに渡す必要があります。フィールドに格納された所有物を所有するオブジェクトIDisposableは、通常、IDisposableそれ自体を実装する必要があります。そのDisposeメソッドは、フィールドがnullであるかどうかをチェックし、そうでない場合はDisposeそれを呼び出す必要があります。

への参照を保持するだけでは、それIDisposableを呼び出す必要があることを意味しないことに注意してくださいDispose。他のコードがそうするつもりがないという合理的な期待がある場合にのみDispose、1つのホールドを呼び出す必要があります。IDisposable

オブジェクトはFinalize、未知のスレッドコンテキストで有用かつ安全な方法でクリーンアップを実行できる場合にのみオーバーライドする必要があります。一般に、オブジェクトはメソッド内のDispose他のオブジェクトを呼び出さないでください。これは、(一部のソースが主張していることに反して)そのようなオブジェクトが存在することが保証されているにもかかわらず、次の条件のいずれかが当てはまる可能性が高いためです。IDisposableFinalize

  1. 他のオブジェクトはまだどこかで使用されている可能性があります。その場合、そのオブジェクトで`Dispose`を呼び出すことは安全ではありません。
  2. 他のオブジェクトはすでに`Finalize`メソッドが呼び出されている可能性があります。その場合、` Dispose`はせいぜい冗長であり、安全ではない可能性があります。
  3. 他のオブジェクトは、その `Finalize`メソッドを実行するようにすでにスケジュールされている可能性があります。その場合、` Dispose`は安全かもしれませんが、冗長になる可能性があります。
  4. 他のオブジェクトはスレッドセーフなクリーンアップをサポートしていない可能性があります。その場合、 `Dispose`の呼び出しは冗長ではないかもしれませんが、安全ではありません。
  5. `Finalizer`が実際に実行できるようになるまでに、やりたいことは何でも意味がないかもしれません(このシナリオではイベントサブスクリプションを考え出すことができます)。

つまり、を所有してIDisposableいる場合は、ファイナライザスレッドのコンテキスト内で安全にクリーンアップできる場合はそれ自体が処理され、できない場合は強制しようとしないでください。

于 2012-05-23T14:52:21.220 に答える
0

投稿するコードはさまざまな目的のためのものです

public class myClass : IDisposable
{
  ...
  public void Dispose()
  {
    myDisposableMem.Dispose();
  }
}

誰か(あなた自身または他の誰か)があなたのクラスのDisposeメソッドを呼び出すと、myDisposableMemそれは正しいことであるdisposeメソッドも呼び出すことを意味します(他のDisposableメンバーがいるmyClass場合は、ここにそれらを含めることを強くお勧めします良い...)

一方で

void main ()
{
  using (myClass myObj = new MyClass())
  {
    .... 
  }
}

myObjISNはすでにクラスのメンバーではなく、usingステートメント内でのみ使用可能であり、後で破棄されることを意味します。

これらは2つの異なるシナリオであり、どちらが自分に当てはまるかを特定する必要があります。myClassすでにクラスのメンバーがいる場合は、他の人が使用しないことが絶対に確実で、そのままにしておくのにかなりのリソースが必要な場合を除いて、それ自体が破棄されるまで破棄しないことを強くお勧めします。

実際のコード/シナリオに関するもう少し洞察があれば、どのアプローチを使用すべきかを教えてくれるかもしれません。

Finalizeが実際にどのように機能するかも考慮に入れてください。この他のSOの質問は、そこで少し役立つかもしれません。

私の意見では、私がここにいることを保証することはできませんが、Dispose()メソッドは、実装オブジェクトがアプリケーションにアクセスできなくなる前に、使用しているすべてのリソースを解放することを確認しますが、finalizeメソッドがスタックから削除されることはありません。実装されると、ガベージコレクション中に呼び出されます。

于 2012-05-23T00:24:48.303 に答える
0

ファイナライズと実装IDisposableは、2つの別個のオプションではありません。それらは常に一緒に行われるべきです。ユーザーが管理されていないリソースをタイムリーにクリーンアップできるように、常にリソースを実装IDisposableしてクリーンアップする必要があります。Dispose()また、Dispose()メソッドは常にGC.SuppressFinalize(this)を呼び出して終了し、ファイナライザーが呼び出されないようにする必要があります。これについては、後で説明します。

~MyObject()を実装するときは、常に実装する必要がありますIDisposable。その目的は、ガベージコレクターに、オブジェクトを使用している人が自分で処理できない場合に備えて、オブジェクトが常に廃棄されるようにする方法を提供することです。ファイナライザーが呼び出し以上のことをしているthis.Dispose()場合は、おそらくそれを誤って使用しています。 いいえ。以下のIlianPinzonのコメントを参照してください。また、もう一度読んでみるためのドキュメントがいくつかあるようです。

それは本当に単なるセーフティネットです。理想的には、オブジェクトは常に明示的に破棄されるため、ファイナライザーは実際には呼び出されないようにする必要があります。ガベージコレクターがそれを呼び出すと、そのオブジェクトの収集をスキップするように強制されます。つまり、ガベージコレクターの第2世代に渡されます。つまり、オブジェクトはメモリ内にずっと長く留まり、最終的にはクリーンアップに費用がかかります。

それがどのように行われるべきかについての詳細は、こことここを参照してください。

とは言うものの、最良のオプションは、それらの使い捨てオブジェクトをクラスコンテキストから外し、可能な限り代わりにメソッド変数にすることです。

たとえば、データベースに接続するクラスがある場合は、のマスターインスタンスをSqlConnectionフィールドとして保存しないでください。代わりに、パブリックメソッドに独自の接続を作成させ、必要に応じてそれらをプライベートメソッドに渡します。これには2つの利点があります。1つは、ブロックで宣言してそれを実行できることを意味しSqlConnectionsますusing。次に、「グローバル」状態のその部分を取り除くことは、必要に応じてスレッドセーフに役立ちます。(`SqlConnectionに固有の他の利点がありますが、それらは一般的なものです。)

于 2012-05-23T00:27:15.307 に答える