Search code examples
c#singletonstreamwriter

Flush StreamWriter at the end of its lifetime


I have a singleton-like class that can do some logging output:

class Foo
{
    private static Foo instance;
    private System.IO.StreamWriter os;

    private Foo()
    {
        this.os = System.IO.File.CreateText( "D:/tmp/test" );
    }

    public static Foo Instance
    {
        get
        {
            if ( instance == null )
                instance = new Foo();
            return instance;
        }
    }

    public void Log( string s )
    {
        os.Write( s );
    }
}

When I use that in a sample program like

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

the file is being created, but no output is written. I assume this is because the StreamWriter has never been flushed.

I tried to repair the class by calling to Close() in ~Foo():

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

but this yields a ObjectDisposedException. Apparently Foo.os has already been disposed when Foo's destructor is called.

How do I ensure that my StreamWriter is flushed "at last"?

EDIT

Setting this.os.AutoFlush = true; works. Adding a Flush() method to Foo and calling it in appropiate places does as well, but I'm interested if there any way of doing without.


Solution

  • First of all, using a singleton creates problems in its own right, and this did not need another proof. Here, it's cleanup for a disguised global. The StreamWriter does not auto-flush on program end and according to the documentation,

    You must call Close to ensure that all data is correctly written out to the underlying stream.

    Thanks to an answer to "Self-closing StreamWriter singleton" from @PeterDuniho a possible solution could be changing the constructor to

    private Foo()
    {
        this.os = System.IO.File.CreateText( "D:/tmp/test" );
        System.AppDomain.CurrentDomain.ProcessExit +=
            (sender, eventArgs) => this.os.Close();
    }
    

    Considering the problem of calling Close() in the destructor, I should not have ignored the "finalizers are not of much use anyway" written all over the place. In this case, as garbage collection does not use a specific order, the StreamWriter object has already been collected and cannot be closed in its resurrected zombie state.