2011-01-08 11 views
3

オブジェクトがGC.SuppressFinalizeを呼び出したかどうかを検出する方法はありますか?オブジェクトがGC.SuppressFinalizeを呼び出したかどうかを検出できますか?

私はこの(わかりやすくするために省略さ本格的にDisposeパターン)のようになりますオブジェクトがあります。ownsResourceコンストラクタのパラメータがfalseである場合には、ファイナライザは何の関係もないだろう

public class ResourceWrapper { 
    private readonly bool _ownsResource; 
    private readonly UnmanagedResource _resource; 

    public ResourceWrapper(UnmanagedResource resource, bool ownsResource) { 
     _resource = resource; 
     _ownsResource = ownsResource; 
     if (!ownsResource) 
      GC.SuppressFinalize(this); 
    } 
    ~ResourceWrapper() { 
     if (_ownsResource) 
      // clean up the unmanaged resource 
    } 
} 

を - そうコンストラクタから右にGC.SuppressFinalizeを呼び出すことは妥当と思われます(ちょっと奇妙な場合)。しかし、この振る舞いは奇妙なので、私はXML文書のコメントでそれを書き留めておきたいと思っています。もし私がコメントするように誘惑されたら、単体テストを書くべきです。

しかしSystem.GCにメソッドがオブジェクトのfinalizability(SuppressFinalizeReRegisterForFinalize)を設定している間、私はオブジェクトのfinalizabilityを取得するために、任意の方法が表示されません。 Typemockを購入したり、自分のCLRホストを作成したりしていない、特定のインスタンスでGC.SuppressFinalizeが呼び出されたかどうかを問い合わせる方法はありますか?

答えて

3

オブジェクトがリソースを所有していない場合にファイナライズが抑制されていることを確認するには、ファイナライザがリソースを所有していると主張できますか?テストではGC.CollectとGC.WaitForPendingFinalizersを実行する必要がありますが、プロダクションコードではアサート以外の余分なものはありません(プロダクションビルドから省略可能)。アサーション付きの警告:オブジェクトの作成と所有権ステータスの設定の間に、オブジェクトを作成するスレッドが終了すると、ファイナライザが不適切に実行される可能性があります。

これまで言われてきたように、リソースの所有者または所有者が異なる別個のサブタイプOwnedResourceWrapperとSharedResourceWrapperを持つ、抽象的なResourceWrapperタイプを持つ方が良いかどうか疑問です。次に、リソースを所有していないサブタイプは、最初にファイナライザを持つ必要はありません。 SharedResourceWrapperがIDisposableをno-opとして実装すると便利な場合があることに注意してください。

+0

どちらも良いアイデアですが、私は第2のものが好きです。「所有者」の責任を別のオブジェクトに移してください。 –

+0

別のオブジェクトタイプを使用すると、IMHOが機能するときにはよりクリーンになります(つまり、リソースが所有されるかどうかをラッパーが認識し、その状態は決して変更されません)。両方のテクニックを利用できることは確かに便利です。上の編集で指摘したように、ファイナライザは実行前にデフォルトに設定されています。これはちょっとしたようですが、ほとんどのシナリオではおそらく問題にはなりません。 – supercat

4

これは不可能ですが、GCはこの情報を提供していません。その理由は、オブジェクトが入ることができるのは2つの状態だけではなく、すでにファイナライズキューに入っているか、既にファイナライズされている可能性があります。

カスタムCLRホストはそれを手伝ってくれません。ホスティングインターフェイスはgcにフックを提供しません。ファイナライザでこれをチェックするだけで、SuppressFinalizeが呼び出されたかどうかを確認することができます。それを記録する(すばやく)。あなたはその反対を証明することはできません。

Fwiw、.NETフレームクラスではこれを行わず、ファイナライザを実行させるだけです。

+0

いくつかのBCLクラスは、実際にそのコンストラクタからSuppressFinalizeを行います。 SqlConnection(ただし、私は条件付きでそれを見たことはありません)。 –

2

これは(reductio absurdum)を助けるかもしれません。トリックは、ファイナライザでいくつかのログ(これは静的な状態になる可能性があります)を行います。誰かがいなくても、抑制のファイナライズを呼びましたが、いつでも確実なことはできません。

あなたがそのタイプの作者である場合、これは機能しています。

+0

私はそれについて考えました。 GC.CollectとGC.WaitForPendingFinalizersをテストから呼び出す必要がありますが、それは実行可能です。しかし、私は生産コードをテストのためだけの余分な作業にするのは嫌です。 –

+0

私はまったくお勧めしませんが、まだ解決策です。たぶん、あなたは他人からのより信頼できる解決策を見つけるでしょう。 – Xaqron

関連する問題