2016-04-08 5 views
1

J'ai essayé de limiter davantage le problème dans Flush StreamWriter at the end of its lifetime la mise en œuvre d'un singleton comme l'auto-fermeture StreamWriter:fermeture automatique StreamWriter singleton

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; 
     } 
    } 
} 

L'effet recherché est que, dans un exemple de programme comme

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

le garbage collector provoque la fermeture de l'instance Foo.

Cela ne fonctionne pas. Apparemment, le StreamWriter est déjà parti quand destructor de Foo fonctionne, et je reçois un System.ObjectDisposedException.

Comment appeler Close() sur le flux de manière à prévenir la perte appropriés et, de données?

+0

J'ai voir le microsoft référence source pour FileStream. Quand le destructeur est appelé, il y a déjà quelques tentatives de vidage, donc pas besoin de faire ce que vous avez fait. Le problème est que GC peut déjà fermer le handle au fichier avant que le dernier vidage ne se produise, il peut donc ne pas fonctionner. Référence: http://referencesource.microsoft.com/#mscorlib/system/io/filestream.cs –

+0

@ThariqNugrohotomo Vous voulez dire le code dans 'FileStream.Dispose'? Je dirais que "Dispose" n'est pas appelé dans mon exemple. – mkluwe

Répondre

2

Apparemment, le StreamWriter est déjà parti lorsque la destructor Foo court

Oui. Au moment de la fin du programme, en supposant que votre objet reçoive la GC du tout (il n'y a aucune garantie que ce sera le cas), le runtime ne fournit aucune garantie sur l'ordre dans lequel il exécute les finaliseurs. Les deux objets sont inaccessibles et peuvent être finalisés en même temps, et leurs finalizers peuvent donc être exécutés dans n'importe quel ordre.

Les finaliseurs sont là seulement en tant que backstop pour le code bogué. Et ils ne sont pas fiables à 100% dans ce but non plus. C'est pourquoi vous devriez travailler dur pour éviter le code buggy.

Vous aurez besoin d'une manière déterministe de disposer l'objet singleton à la sortie du processus. Vous pouvez mettre ceci dans le contrôle de la logique principale de votre programme, qui contrôle la durée de vie du processus, et lui faire disposer le singleton (par exemple via une méthode publique que vous écrivez à cette fin). Une autre alternative consiste à vous abonner à l'événement AppDomain.ProcessExit dans le constructeur de votre singleton, et d'y faire fermer le singleton par le gestionnaire.

Voir ces questions connexes pour plus d'informations:
How can I ensure that I dispose of an object in my singleton before the application closes?
Disposable singleton in C#

+0

Pour mémoire: j'ai ajouté 'System.AppDomain.CurrentDomain.ProcessExit + = (expéditeur, eventArgs) => this.Close();' dans le constructeur et enlevé le destructor pour rendre ce code jouet à la pièce. – mkluwe