10
 class Program : CriticalFinalizerObject
    {
        static void Main(string[] args)
        {

            Program p = new Program();
            TextWriterTraceListener listener = new TextWriterTraceListener(@"C:\trace.txt");
            Trace.Listeners.Clear(); // Remove default trace listener
            Trace.Listeners.Add(listener);
            Trace.WriteLine("First Trace"); // Generate some trace messages
            Trace.WriteLine("Perhaps last Trace.");

        }

        ~Program()
        {
            Trace.Close();
        }
    }

ファイルサイズ=0を取得します

私はから派生しているので、finilizerは実行されるべきでしたCriticalFinalizerObject

FinalizerではなくTrace.Close()を使用したくありません。

編集

@eric Lippertの返信後:コードを次のように一致させようとして再編集しました:制約された実行領域 (ただし、まだ成功していません)

  [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
    class Program : CriticalFinalizerObject
    {

        static void Main(string[] args)
        {
            RuntimeHelpers.PrepareConstrainedRegions();
            try
            {
            }
            catch (Exception e)
            {
            }
            finally
            {
                Program p = new Program();
                TextWriterTraceListener listener = new TextWriterTraceListener(@"C:\trace1.txt");
                Trace.Listeners.Clear();
                Trace.Listeners.Add(listener);
                Trace.WriteLine("First Trace");
                Trace.WriteLine("Perhaps last Trace.");
            }
        }

        ~Program()
        {
            Trace.Flush();
        }
    }
4

3 に答える 3

11

ドキュメントに明確に記載されているように:

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

ファイナライザーは、制約された実行領域のすべてのルールに従いますか?

アップデート:

制約された実行領域のルールに準拠するようにコードを更新しましたが、正しく実行したという証拠はありません。ルールは非常に明確です。制約された実行領域のファイナライザーは、次のことを絶対に実行してはなりません

  • メモリを割り当てる
  • ボックス値タイプ
  • ロックを取得する
  • 任意の仮想メソッドを呼び出す
  • 信頼性契約がないメソッドを呼び出す

あなたのファイナライザーはこれらの5つのことのいずれかを行いますか?その場合、CLRがファイナライザーを常に実行するというユーザーの要望を尊重する必要はありません。

さらに、現在のプログラムはスレッドセーフでさえないため、制約された実行領域についてはしばらく忘れてください。プログラムに厄介な競合状態を書き込みました。

トレースが開始する前に、ガベージコレクションpからジッターを停止するものは何ですか?何もない!ジッタは、pが二度と使用されないことを認識しており、割り当て直後にpを収集する権利の範囲内にあります。フラッシュは、トレース書き込みが発生する前、またはそれらのいずれかの途中を含め、ファイナライザスレッドでいつでも発生する可能性があります。

于 2012-04-06T13:53:50.023 に答える
10

Programクラスのインスタンスを作成しなかったためです。

あなたはここでもっと読むことができます:

このメソッドは、オブジェクトがSuppressFinalizeの呼び出しによってファイナライズから除外されていない限り、オブジェクトにアクセスできなくなった後に自動的に呼び出されます。アプリケーションドメインのシャットダウン中に、ファイナライズが免除されていないオブジェクト(まだアクセス可能なオブジェクトであっても)に対して、ファイナライズが自動的に呼び出されます。Finalizeは、ReRegisterForFinalizeやGC.SuppressFinalizeなどのメカニズムを使用してオブジェクトが再登録されていない限り、特定のインスタンスで1回だけ自動的に呼び出されます。

したがって、finilizerを呼び出す場合は、オブジェクトのインスタンスが必要です。

更新:Trace.AutoFlush = true;メッセージを書きたい場合は、の使用を検討してください。

更新:(なぜClose関数が呼び出されないのですか?)実際には、Close関数が呼び出されます(他のファイナライザーで例外が発生しない場合)。デフォルトのTraceListener(Trace.Listeners.Clear()呼び出しの削除)を維持すると、すべての文字列が出力ウィンドウに正常に書き込まれたことがわかります。

ここでの問題は、StreamWriter(TextWriterTraceListener内に作成されます)にファイナライザーがないことです。したがって、すべてのデータをファイルにフラッシュするわけではありません。するべきこと:

FileStream file = new FileStream(@"C:\trace.txt", FileMode.OpenOrCreate);
StreamWriter writer = new StreamWriter(file);
GC.SuppressFinalize(file);
GC.SuppressFinalize(file.SafeFileHandle);
var listener = new TextWriterTraceListener(writer);

実際には、ファイナライザーでファイルを手動で閉じる必要があります。

于 2012-04-06T13:18:27.290 に答える
0

C#では、GCがそれを処理するため、ファイナライザーがいつ呼び出されるか、または呼び出されるかどうかを確認できません。したがって、リリースするリソースがある場合は、次のIDisposableように実装して使用するクラスを作成することをお勧めします。

using (MyResourceHolder rh = new MyResourceHolder()) {
    // ...
} // rh.Dispose() is called implicitly

Disposeメソッドでは、を呼び出すことができますTrace.Close()

の適切な実装については、http://msdn.microsoft.com/en-us/library/system.idisposable.aspxを参照してくださいIDisposable

于 2012-04-06T13:38:44.150 に答える