DotNet Events

Overview

At runtime, I am planning to have several way of logging defined in a config file. I wanted to prevent looping throught the different loggers and I thought using events might be a good way to solve this.

Subscribers

This is the simplest implementation for Console output. A constructor accepting a Dictionary is used to configure anytype of Logger. The Log method was the default method used to push the logs. HandleLog is simply the event triggered by the Publisher. Dispose is used to dispose cleanly the ressources when the applciaiton is closed. (Files, db connections, etc…)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    public class ConsoleLog : ILog, IDisposable
    {
        public ConsoleLog (Dictionary<string, string> parameters)
        { }

        public void Log(LogStruct message)
        {
                Console.ForegroundColor = message.Color;
                if (message.IsNewLine)
                    Console.WriteLine(message.Message);
                else
                    Console.Write(message.Message);
        }

        public void HandleLog(object sender, LogEventArgs e)
        {
            Log(e.Log);
        }

        public void Dispose()
        {
        }
    }

Data structures passed through the event

ILog interface to decouple the implementation :

1
2
3
4
5
6
    public interface ILog
    {
        public void Log(LogStruct message);
        public void HandleLog(object sender, LogEventArgs e);
        public void Dispose();
    }

The event to trigger is called HandleLog. The parameter to pass to the event is defined with LogEventArgs.

1
2
3
4
5
6
7
8
9
    public class LogEventArgs : EventArgs
    {
        public LogStruct Log { get; set; }

        public  LogEventArgs (LogStruct message)
        {
            Log = message;
        }
    }

Publisher

Defining a list of subscribers and the event handler :

1
2
    private List<ILog> loggers = new List<ILog>();
    private event EventHandler<LogEventArgs> _logEvent ;

To initialize the logengine, we first need to parse all the loggers required, instantiate them using Dependency Injection, then collectin them in the list. For each logger, we register the EventHandler this way :

1
2
3
4
    ...
    _logEvent += iLogInstance.HandleLog;
    logger.Add(iLogInstance);
    ...

Then when logging, we simply trigger an event :

1
    _logEvent?.Invoke(queue, new LogEventArgs(message));

The variable message being a data structure of type LogStruct, as defined in the LogEventArgs.

Each time the event is triggered, all the events registered are being called at the same time, without needed to loop through the list.

Conclusion

This is a bit more complex to put in place, but each time the application has to log something, it doesnt need to loop through all the loggers. Only when initializing the application and when disposing the application do we need to loop through the loggers. Yet disposing the Loggers is not really required, but I prefer to do it nonetheless, to keep a clean state. (closing properly files, and other ressources.) I have used events in the past within graphical interfaces, but never for a case like this. Or not explicitly, as this is probably how the MEL is working under the hood. I am still pondering the benefits, what are the differences in term of memory / cpu ressources compared to not using events.