I was writing an application using a MVP pattern and was contemplating the mechanism for components to bubble status info and other types of messages up to each other and also to the main container form (for a win app).
The first step was to create a container type to hold the message that I want to pass around. Because the message bus needs to be able to notify observers of new messages I derived the message container from the base EventArgs class as such:
public class MessageBusEventArgs<T> : EventArgs
{
private T _message;
public MessageBusEventArgs(T Message)
{
_message = Message;
}
public T Message
{
get
{
return _message;
}
}
}
Now the real value of a message bus is to allow any interested parties to register / unregister from a single source. In order to accomplish this we need a threadsafe singleton implementation for the actual MessageBus:
public class MessageBus<T>
{
private static MessageBus<T> _instance = null;
private static readonly object _lock = new object();
protected MessageBus()
{
}
public static MessageBus<T> Instance
{
get
{
lock (_lock)
{
if (_instance == null)
{
_instance = new MessageBus<T>();
}
return _instance;
}
}
}
}
So now we have a very usefull shell that does nothing. In order to allow interested parties to register to be notified of a new messages we need to add an event register. And finally we need a method to allow message senders to broadcast the messages out. To implement this we add the following to the MessageBus class:
public event EventHandler<MessageBusEventArgs<T>> MessageRecieved;
public void SendMessage(object sender, T Message)
{
if (MessageRecieved != null)
{
MessageRecieved(sender, new MessageBusEventArgs<T>(Message));
}
}
Okay, now we have a working MessageBus.
Without the generic on the classes we would have to create one of these for each message type that we want to handle but with the generic we are able to handle any type that the end user can dream up.
For anyone not familiar with generics, the compiler creates a completly separate definition of the generic class for each generic type used with it.
For example:
Type gtMessageBusInt = typeof(MessageBus<int>);
Type gtMessageBusString = typeof(MessageBus<string>);
Type gtMessageBusInt2 = typeof(MessageBus<int>);
gtMessageBusInt != gtMessageBusString
gtMessageBusInt == gtMessageBusInt2
It is exactly this property of generics that allows the message bus to enable opt in registration for each type of message.
This post is getting a bit long now so I'll end here and follow up shortly with an implementation example using the MessageBus<T>.