2016-04-08 6 views
1

Ich habe versucht, das Problem in Flush StreamWriter at the end of its lifetime Implementierung eines Singleton artige selbstschließ StreamWriter weiter zu verengen:Selbstschließender Stream Singletons

class Foo : System.IO.StreamWriter 
{ 
    private static readonly Foo instance = new Foo("D:/tmp/test"); 

    private Foo(string path) 
     : base(path) 
    { 
    } 

    ~Foo() 
    { 
     this.Close(); 
    } 

    public static Foo Instance 
    { 
     get 
     { 
      return instance; 
     } 
    } 
} 

Die beabsichtigte Wirkung ist, dass in einem Beispielprogramm wie

class Program 
{ 
    private static void Main(string[] args) 
    { 
     Foo.Instance.Write("asdf\n"); 
    } 
} 

Der Garbage Collector bewirkt, dass die Instanz Foo geschlossen wird.

Dies funktioniert nicht. Anscheinend ist die StreamWriter bereits weg, als Foo Destruktor ausgeführt wird, und ich bekomme eine System.ObjectDisposedException.

Wie rufe ich Close() auf dem Strom in einer geeigneten Weise an und verhindern Sie Verlust von Daten?

+0

ich sehe haben die Referenzquelle von Microsoft für Filestream. Wenn der Destruktor aufgerufen wird, gibt es bereits einen Versuch, in die Datei zu spülen, also müssen Sie nicht tun, was Sie getan haben. Das Problem besteht darin, dass GC das Handle für die Datei bereits vor dem letzten Leeren schließt, sodass es möglicherweise nicht funktioniert. Referenz: http://referencesource.microsoft.com/#mscorlib/system/io/filestream.cs –

+0

@ThariqNugrohotomo Sie meinen den Code in 'FileStream.Dispose'? Ich würde sagen, dass 'Dispose' in meinem Beispiel nicht aufgerufen wird. – mkluwe

Antwort

2

Offenbar wird der Stream schon weg, wenn Foo destructor

läuft

Ja. Bei der Beendigung des Programms, vorausgesetzt, Ihr Objekt wird überhaupt gecodiert (es gibt keine Garantie, dass es sein wird), die Laufzeit bietet keine Garantien über die Reihenfolge, in der Finalisten ausgeführt wird. Beide Objekte sind nicht erreichbar und können gleichzeitig finalisiert werden, sodass ihre Finalizer in beliebiger Reihenfolge ausgeführt werden können.

Finalizer gibt es nur als Backstop für Buggy-Code. Und sie sind auch nicht zu 100% zuverlässig. Deshalb sollten Sie hart arbeiten, um fehlerhaften Code zu vermeiden.

Sie benötigen eine deterministische Möglichkeit, das Singleton-Objekt beim Prozess-Exit zu entfernen. Sie können dies in die Steuerung der Hauptlogik Ihres Programms einfügen, die die Prozesslebensdauer steuert, und es veranlassen, dass der Singleton (z. B. über eine öffentliche Methode, die Sie für diesen Zweck schreiben) verfügt. Eine weitere Alternative besteht darin, das Ereignis AppDomain.ProcessExit im Konstruktor Ihres Singletons zu abonnieren und den Handler den Singleton dort schließen zu lassen.

Sehen Sie diese Fragen für weitere Informationen:
How can I ensure that I dispose of an object in my singleton before the application closes?
Disposable singleton in C#

+0

Für den Eintrag: Ich habe 'System.AppDomain.CurrentDomain.ProcessExit + = (sender, eventArgs) => this.Close(); 'im Konstruktor hinzugefügt und den Destruktor entfernt, damit dieser Spielzeugcode funktioniert. – mkluwe