1

I tried to further narrow down the problem in Flush StreamWriter at the end of its lifetime implementing a singleton-like self-closing StreamWriter:

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

The intended effect is that in a sample program like

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

the garbage collector causes the instance of Foo to be closed.

This does not work. Apparently, the StreamWriter is already gone when Foo's destructor runs, and I get a System.ObjectDisposedException.

How do I call Close() on the stream in an appropiate way and prevent loss of data?

Community
  • 1
  • 1
mkluwe
  • 3,823
  • 2
  • 28
  • 45
  • I have see the microsoft's reference-source for FileStream. When the destructor is called, there is already some attemp to flush to file, thus no need to do what you did. The problem is, GC may already close the handle to the file before that last flush occurs, so it may not working. Reference: http://referencesource.microsoft.com/#mscorlib/system/io/filestream.cs – Thariq Nugrohotomo Apr 08 '16 at 15:45
  • @ThariqNugrohotomo You mean the code in `FileStream.Dispose`? I'd say that `Dispose` does not get called in my example. – mkluwe Apr 08 '16 at 15:55

1 Answers1

2

Apparently, the StreamWriter is already gone when Foo's destructor runs

Yes. At program termination, assuming your object gets GC'ed at all (there's no guarantee it will be), the runtime doesn't provide any guarantees about the order in which it executes finalizers. Both objects are unreachable and eligible for finalization at the same time, and so their finalizers could run in any order.

Finalizers are there only as a backstop for buggy code. And they are not 100% reliable for that purpose either. It's why you should work hard to avoid buggy code.

You'll need a deterministic way to dispose the singleton object on process exit. You can put this into the control of your program's main logic, which is controlling the process lifetime, and have it dispose the singleton (e.g. via a public method you write for that purpose). Another alternative is to subscribe to the AppDomain.ProcessExit event in your singleton's constructor, and have the handler close the singleton there.

See these related questions for additional information:
How can I ensure that I dispose of an object in my singleton before the application closes?
Disposable singleton in C#

Community
  • 1
  • 1
Peter Duniho
  • 68,759
  • 7
  • 102
  • 136
  • For the record: I added `System.AppDomain.CurrentDomain.ProcessExit += (sender, eventArgs) => this.Close();` in the constructor and removed the destructor to make this toy code piece work. – mkluwe Apr 09 '16 at 15:14