2008-11-01 8 views
36

Was ist der richtige Weg, um eine statische Finalisierung durchzuführen?Statischer Finalizer

Es gibt keinen statischen Destruktor. Das Ereignis AppDomain.DomainUnload wird in der Standarddomäne nicht ausgelöst. Das Ereignis AppDomain.ProcessExit teilt die Gesamtzeit der drei Sekunden (Standardeinstellungen) zwischen allen Ereignishandlern, daher ist es nicht wirklich brauchbar.

+2

Zunächst müssen wir in C# aus der Gewohnheit herauskommen, Finalizer und Destruktor austauschbar zu verwenden. Das eine ist deterministisch, das andere nicht. Es ist interessant festzustellen, dass die C# -Spezifikation die Ausdrücke aus der CLR und anderen .NET-Sprachspezifikationen zurückerhält.Es ist auch interessant zu bemerken, dass die Anmerkungen des C# Sprachkomitees ausdrücklich sagen, dass es keine vorhersehbaren Gründe gibt, warum C# keine statischen Finalizer haben kann. http://StackOverflow.com/a/1875149/56793 – JMD

Antwort

27

Grundsätzlich können Sie nicht. Entwirf dich so gut wie möglich.

Vergessen Sie nicht, dass ein Programm immer abrupt sowieso abbrechen kann - jemand, der die Macht herauszieht, die das offensichtliche Beispiel ist. Also muss alles, was Sie tun, "Best Effort" sein - in diesem Fall würde ich sicherlich hoffen, dass AppDomain.ProcessExit wäre gut genug.

Was müssen Sie in Ihrem speziellen Fall tun?

+1

Wie bezieht sich diese Antwort auf die Antwort von Michael (da es möglich ist, statische Finalizer zu haben)? (So ​​oder so stimme ich zu, dass Finalizer unzuverlässig sind.) – mafu

+0

@mafutrct: Michaels Antwort ist nicht wirklich ein statischer Finalizer. Es ist ein statisches Feld mit einem Verweis auf eine Instanz mit einem Finalizer. Es ist nicht dasselbe, obwohl es ähnliche Auswirkungen haben könnte. Ich würde es nicht persönlich benutzen. –

+0

Eigentlich hast du völlig recht. Danke für die Erklärung! – mafu

6

Ich würde fragen, was Sie in Ihren statischen Methoden laden, die veröffentlicht werden müssen. Ich würde sicherlich nicht empfehlen, diese Dinge in einer statischen Methode zu tun.

Das heißt, Ihre statische Methode konnte ein Objekt instanziieren, das eine Finalize-Methode hat.

6

Zwei Lösungen, die den Sinn springen:

  • Sie eine statische Klasse nicht verwenden. Wenn Sie eine nicht statische Klasse verwenden und sie instanziieren, müssen Sie sich keine Gedanken über die Bereinigung machen.
  • Wenn das keine Option ist, würde ich argumentieren, dass dies eine gute Situation ist, ein Singleton zu verwenden. Dadurch wird eine Kopie Ihres Objekts instanziiert und der Finalizer beim Beenden aufgerufen. Sie können ihn jedoch weiterhin wie eine statische Klasse behandeln. Schließlich ist Ihre Klasse bereits statisch und teilt daher die meisten der üblichen Gründe, kein Singleton zu verwenden.
39

Herfried Wagner hat eine excellent article geschrieben zu erklären, wie dies umzusetzen - ach, in Deutsch (und VB). Dennoch sollte der Code verständlich sein.

Ich habe es versucht:

static readonly Finalizer finalizer = new Finalizer(); 

sealed class Finalizer { 
    ~Finalizer() { 
    Thread.Sleep(1000); 
    Console.WriteLine("one"); 
    Thread.Sleep(1000); 
    Console.WriteLine("two"); 
    Thread.Sleep(1000); 
    Console.WriteLine("three"); 
    Thread.Sleep(1000); 
    Console.WriteLine("four"); 
    Thread.Sleep(1000); 
    Console.WriteLine("five"); 
    } 
} 

Es scheint, die gleiche Art und Weise genau zu arbeiten, wie das AppDomain.ProcessExit Ereignis macht: die Finalizerthread bekommt ca. drei Sekunden ...

+3

Dies ist die beste Antwort, da Sie Ihren "Finalisierer" auf diese Weise debuggen können, während die AppDomain. Der ProcessExit-Delegat erlaubt Ihnen nicht, es zu debuggen (zumindest in meiner Erfahrung). –

0

Um Michael Damatovs Antwort (C#) zu portieren, die auf Herfried K. Wagner basiert. (VB.NET) ist hier die C++/CLI-Version:

ref class MyClass 
{ 
     ref class StaticFinalizer sealed 
     { 
      !StaticFinalizer(); 
     }; 
     static initonly StaticFinalizer^ stDestr = gcnew StaticFinalizer(); 
} 

MyClass::StaticFinalizer::!StaticFinalizer() 
{ 
    System::Diagnostics::Debug::WriteLine("In StaticFinalizer!"); 
} 

P.S. Genau wie die AppDomain.ProcessExit-Methode wird diese möglicherweise nicht aufgerufen, wenn der Prozess abnormal beendet wird (z. B. vom Task-Manager). Ein anderes Wort der Warnung ist, dass, wenn MyClass generisch ist (templated), die Annahme, dass sein statischer Konstruktor und der statische Destruktor nicht mehr als einmal pro Anwendungsausführung aufgerufen werden, nicht länger gültig ist.