Traditional Event Handling

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/69fe3e38-28d0-4bb2-bd4b-00c5c25518fa/Untitled.png

public class EventAggregatorMainApp
{
	private readonly IPublisher<int> IntPublisher;
	private readonly Subscriber<int> IntSublisher1;
	private readonly Subscriber<int> IntSublisher2;

	public EventAggregatorMainApp()
	{
		IntPublisher = new Publisher<int>();

		IntSublisher1 = new Subscriber<int>(IntPublisher);
		IntSublisher1.Publisher.DataPublisher += Publisher_DataPublisher1;

		IntSublisher2 = new Subscriber<int>(IntPublisher);
		IntSublisher2.Publisher.DataPublisher += Publisher_DataPublisher2;

		IntPublisher.PublishData(10);
	}

	private void Publisher_DataPublisher1(object sender, MessageArgument<int> e) => 
		Console.WriteLine("Subscriber 1 : " + e.Message);

	private void Publisher_DataPublisher2(object sender, MessageArgument<int> e) => 
		Console.WriteLine("Subscriber 2 : " + e.Message);
}

public class MessageArgument<T> : EventArgs
{
	public T Message { get; set; }
	public MessageArgument(T message)
	{
		Message = message;
	}
}

public interface IPublisher<T>
{
	event EventHandler<MessageArgument<T>> DataPublisher;
	void OnDataPublisher(MessageArgument<T> args);
	void PublishData(T data);
}

public class Publisher<T> : IPublisher<T>
{
	public event EventHandler<MessageArgument<T>> DataPublisher;
	public void OnDataPublisher(MessageArgument<T> args) => DataPublisher?.Invoke(this, args);

	public void PublishData(T data)
	{
		MessageArgument<T> message = (MessageArgument<T>)Activator.CreateInstance(typeof(MessageArgument<T>), new object[] { data });
		OnDataPublisher(message);
	}
}

public class Subscriber<T>
{
	public IPublisher<T> Publisher { get; private set; }
	public Subscriber(IPublisher<T> publisher)
	{
		Publisher = publisher;
	}
}

Disadvantages of Traditional Event Handling

Event Aggregator

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/7b9a833b-59af-4482-b774-6b216f2bad3e/Untitled.png

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/694d426a-d2f4-4347-ae95-187e2b05e91c/Untitled.png

public static class EventAggregatorMainApp
{
	public static void Main()
	{
		var eventAggregator = new EventAggregator();
		SubscriberA subscriber1 = new SubscriberA(eventAggregator);
		subscriber1.Subscribe();
		
		SubscriberB subscriber2 = new SubscriberB(eventAggregator);
		subscriber2.Subscribe();
							   
		Publisher publisher1 = new Publisher(eventAggregator);
		publisher1.PublishMessage(new SampleEvent("Sample Message 1"));

		Publisher publisher2 = new Publisher(eventAggregator);
		publisher2.PublishMessage(new SampleEvent("Sample Message 2"));

		subscriber2.Unsubscribe();

		publisher1.PublishMessage(new SampleEvent("Sample Message 3"));
		publisher2.PublishMessage(new SampleEvent("Sample Message 4"));
	}
}    

public interface IEventAggregator
{
	void Subscribe<TEvent>(Action<TEvent> subscriber);
	void Publish<TEvent>(TEvent publishedEvent);
	void Unsubscribe<TEvent>(Action<TEvent> subscriber);
}

public class EventAggregator : IEventAggregator
{
	private Dictionary<Type, List<object>> _Subscribers = new Dictionary<Type, List<object>>();
	readonly static object _Sync = new object();

	public void Subscribe<TEvent>(Action<TEvent> subscriber)
	{
		var eventType = typeof(TEvent);
		lock (_Sync)
		{ 
			if (_Subscribers.TryGetValue(eventType, out List<object> handlers))
				handlers.Add(subscriber);
			else _Subscribers.Add(eventType, new List<object> { subscriber });
		}
	}

	public void Publish<TEvent>(TEvent publishedEvent)
	{
		var eventType = typeof(TEvent);
		lock (_Sync)
		{
			if (_Subscribers.TryGetValue(eventType, out List<object> handlers))
				foreach (var handler in handlers.Cast<Action<TEvent>>())
					handler?.Invoke(publishedEvent);
		}
	}        

	public void Unsubscribe<TEvent>(Action<TEvent> subscriber)
	{
		var eventType = typeof(TEvent);
		lock (_Sync)
		{
			if (_Subscribers.TryGetValue(eventType, out List<object> handlers) && handlers.Contains(subscriber))
				handlers.Remove(subscriber);
		}                
	}
}

public class SampleEvent
{
	public string Message { get; set; }
	public SampleEvent(string message) => Message = message;
}

public interface IPublisher<TEvent>
{
	void PublishMessage(TEvent eventToPublish);
}

public class Publisher : IPublisher<SampleEvent>
{
	private IEventAggregator _EventAggregator;
	public Publisher(IEventAggregator eventAggregator) => _EventAggregator = eventAggregator;
	public void PublishMessage(SampleEvent eventToPublish) => _EventAggregator.Publish(eventToPublish);
}

public interface ISubscriber<TEvent>
{
	void Subscribe();
	void Unsubscribe();
}

public class SubscriberA : ISubscriber<SampleEvent>
{
	private IEventAggregator _EventAggregator;
	public SubscriberA(IEventAggregator eve) => _EventAggregator = eve;
	public void Subscribe() => _EventAggregator.Subscribe<SampleEvent>(Subscriber);
	public void Unsubscribe() => _EventAggregator.Unsubscribe<SampleEvent>(Subscriber);

	private static void Subscriber(SampleEvent publishedEvent) => Console.WriteLine("S1: {0}", publishedEvent.Message);
}

public class SubscriberB : ISubscriber<SampleEvent>
{
	private IEventAggregator _EventAggregator;
	public SubscriberB(IEventAggregator eve) => _EventAggregator = eve;
	public void Subscribe() => _EventAggregator.Subscribe<SampleEvent>(Subscriber);
	public void Unsubscribe() => _EventAggregator.Unsubscribe<SampleEvent>(Subscriber);

	private static void Subscriber(SampleEvent publishedEvent) => Console.WriteLine("S2: {0}", publishedEvent.Message);
}