7

私はこのようなテストコードを持っています:

public class A : CriticalFinalizerObject 
{
    ~A()
    {
        File.WriteAllText("c:\\1.txt", "1z1z1");
    }
}

class Program
{
    static void Main(string[] args)
    {
        A a = new A();
        throw new Exception();
    }
}

まず、CriticalFinalizerObjectからAを取得せずに実行してみました。このプログラムの終了後、ファイナライザーは呼び出されませんでした。それはもっと決定論的だと思ったので、それは私を驚かせましたが、大丈夫です。次に、ファイナライザーが確実に呼び出されるようにするCriticalFinalizerObjectについて読みました。私はそれからAを導き出しました。何だと思う。それでも実行されません。私は何をしている/間違っていると理解していますか?

(ガベージコレクターが非決定的であることについて明白なことを書かないでください。私はそれを知っています。プログラムが終了し、処理されていない管理された例外の後で安全にクリーンアップできると想像したので、そうではありません。)

4

2 に答える 2

10

まず、MSDNのCriticalFinalizerObjectについて読みましょう。次のように読むことができます。

CriticalFinalizerObjectクラスから派生したクラスでは、共通言語ランタイム(CLR)は、CLRがアプリケーションドメインを強制的にアンロードする状況でも、ファイナライザーがCERのルールに従っている場合、すべての重要なファイナライズコードが実行される機会を保証します。またはスレッドを中止します。

ここでの主な言葉はUNLOADです。

次に、 MSDNをもう一度読みましょう。今回は、マネージスレッドの例外について説明します。

これらの例外がメインスレッド、またはアンマネージコードからランタイムに入ったスレッドで処理されない場合、それらは正常に進行し、アプリケーションが終了します。

主な言葉はTERMINATIONです。

したがって、メインスレッドに未処理の例外がある場合、アプリは終了しますが、CriticalFinalizerObjectはドメインのアンロードにのみ役立ちます。

たとえば、CriticalFinalizerObjectは、次のような状況で役立ちます。

// Create an Application Domain:
AppDomain newDomain = AppDomain.CreateDomain("NewApplicationDomain");

// Load and execute an assembly:
newDomain.ExecuteAssembly(@"YouNetApp.exe");

//Unload of loaded domain
AppDomain.Unload(newDomain);

これは、ドメインがアンロードされ、CriticalFinalizerObjectがファイナライザーが呼び出されることを保証する状況です。

アプリの終了を伴うあなたの状況では、あなたは購読を試みることができます

AppDomain.CurrentDomain.UnhandledException

オブジェクトを手動でファイナライズします。

UPD: Jeffrey Richterは、彼の著書「CLR via C#」で、CriticalFinalizerObjectについて書いています。これは、たとえば、C#をプロシージャとして実行できるSQLServerにコードを送信する場合に使用します。このような場合、SQLServerがライブラリのドメインをアンロードする場合、CriticalFinalizerObjectはオブジェクトをクリーンアップするのに役立ちます。また、CriticalFinalizerObjectは、オブジェクトのファイナライザーで別のオブジェクトのメソッドを呼び出す必要がある場合に使用します。CriticalFinalizerObjectは、CriticalFinalizerObject以外のすべてのオブジェクトのファイナライザーの後にファイナライザーが呼び出されることを保証します。

于 2012-05-18T17:00:53.003 に答える
0

Ok。簡単なテストを書きました。Aオブジェクトを作成するコンストラクターに例外がある場合、実際にファイナライザーを機能させることはできませんでしたが、他のクラスのコンストラクターではなく他のメソッドでAオブジェクトを作成し、例外をスローすると機能しました。

したがって、コンストラクターがクラスの構築を完了せず、その作成が終了した場合、オブジェクトが作成されたり、スタックがクリアされたり、オブジェクトが発生しないようにファイナライズせずにヒープから削除されたりすることはないと思います。

それは私の推測です。しかし、この問題を解決するために、重要な構築コード構築オブジェクトをtry-catch-finallyでラップし、クリーンアップコードを明示的に呼び出します。

例:これはうまくいきました

  public Form1()
       {
           InitializeComponent();
       }
       protected override void OnLoad(EventArgs e)
       {
           base.OnLoad(e);
           var a = new A();
           throw new Exception();
       }
   }

これはしませんでした

public Form1()
       {
           InitializeComponent();
           var a = new A();
           throw new Exception();
       }

   }
于 2012-05-18T16:14:07.033 に答える