HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Async file writer in .Net 3.5

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
asyncnetfilewriter

Problem

I'm curious what people think about this little bit of logging code. It seems to work ok. Is there anything I'm missing?

public static class Logger
{
    private static readonly object Locker = new object();
    private static readonly StreamWriter Writer = 
                        new StreamWriter("c:\\temp\\logtester.log", true) ;

    public static void Log(string message)
    {
        Action action = MessageWriter;
        action.BeginInvoke(message, null, null);
    }

    private static void MessageWriter(string message)
    {
        lock(Locker)
        {
            Writer.WriteLine(message);
        }
    }
}


Using Jesse's code, but with QueueUserWorkItem instead of BeginInvoke.

public sealed class Logger : IDisposable
{
    private static readonly object Locker = new object();
    private static readonly StreamWriter Writer = new StreamWriter("c:\\temp\\logtester.log", true);
    private static bool _disposed;

    public static void Log(string message)
    {
        ThreadPool.QueueUserWorkItem(MessageWriter, message);
    }

    private static void MessageWriter(object message)
    {
        if (!(message is string)) return;
        lock (Locker)
        {
            Writer.WriteLine(message);
        }
    }

    ~Logger()
    {
        Dispose(false);
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    private void Dispose(bool disposing)
    {
        lock (Locker)
        {
            if (_disposed)
                return;

            if (disposing)
            {
                if (Writer != null)
                    Writer.Dispose();
            }

            _disposed = true;
        }
    }
}

Solution

Here's a slightly different version. It implements IDisposable so that the StreamWriter can eventually be closed and disposed properly and also uses a typed delegate for asynchronous invocation and properly calls EndInvoke upon completion.

public sealed class Logger : IDisposable
{
    private delegate void WriteMessage(string message);
    private static readonly Logger Instance = new Logger("c:\\temp\\logtester.log");
    private readonly object Locker = new object();
    private readonly StreamWriter Writer;
    private bool Disposed;

    private Logger(string logFileName)
    {
        Writer = new StreamWriter(logFileName, true);
    }

    ~Logger()
    {
        Dispose(false);
    }

    public static void Log(string message)
    {
        WriteMessage action = Instance.MessageWriter;
        action.BeginInvoke(message, MessageWriteComplete, action);
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    private static void MessageWriteComplete(IAsyncResult iar)
    {
        ((WriteMessage)iar.AsyncState).EndInvoke(iar);
    }

    private void Dispose(bool disposing)
    {
        lock (Locker)
        {
            if (Disposed)
            {
                return;
            }

            if (disposing)
            {
                if (Writer != null)
                {
                    Writer.Dispose();
                }
            }

            Disposed = true;
        }
    }

    private void MessageWriter(string message)
    {
        lock (Locker)
        {
            if (!Disposed && (Writer != null))
            {
                Writer.WriteLine(message);
            }
        }
    }
}

Code Snippets

public sealed class Logger : IDisposable
{
    private delegate void WriteMessage(string message);
    private static readonly Logger Instance = new Logger("c:\\temp\\logtester.log");
    private readonly object Locker = new object();
    private readonly StreamWriter Writer;
    private bool Disposed;

    private Logger(string logFileName)
    {
        Writer = new StreamWriter(logFileName, true);
    }

    ~Logger()
    {
        Dispose(false);
    }

    public static void Log(string message)
    {
        WriteMessage action = Instance.MessageWriter;
        action.BeginInvoke(message, MessageWriteComplete, action);
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    private static void MessageWriteComplete(IAsyncResult iar)
    {
        ((WriteMessage)iar.AsyncState).EndInvoke(iar);
    }

    private void Dispose(bool disposing)
    {
        lock (Locker)
        {
            if (Disposed)
            {
                return;
            }

            if (disposing)
            {
                if (Writer != null)
                {
                    Writer.Dispose();
                }
            }

            Disposed = true;
        }
    }

    private void MessageWriter(string message)
    {
        lock (Locker)
        {
            if (!Disposed && (Writer != null))
            {
                Writer.WriteLine(message);
            }
        }
    }
}

Context

StackExchange Code Review Q#13248, answer score: 2

Revisions (0)

No revisions yet.