Created
October 8, 2017 18:35
-
-
Save codemaster/98d4fc773912a899752e42a2d4f71116 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
#if NET_4_6 | |
using System.Threading.Tasks; | |
#endif | |
/// <summary> | |
/// Event manager | |
/// </summary> | |
public class EventManager : IEventManager | |
{ | |
/// <summary> | |
/// Handlers - type to hashset of actions | |
/// </summary> | |
private readonly Dictionary<Type, object> _handlers | |
= new Dictionary<Type, object>(); | |
/// <summary> | |
/// Adds a handler | |
/// </summary> | |
/// <returns><c>true</c>, if handler was added, <c>false</c> otherwise.</returns> | |
/// <param name="handler">The handler.</param> | |
/// <typeparam name="T">The type that this handler is listening for</typeparam> | |
public bool AddHandler<T>(Action<T> handler) | |
{ | |
if (null == handler) | |
{ | |
throw new ArgumentNullException(nameof(handler)); | |
} | |
var handlerSet = GetOrCreateHandlerSet<T>(); | |
return handlerSet.Add(handler); | |
} | |
/// <summary> | |
/// Removes a handler. | |
/// </summary> | |
/// <returns><c>true</c>, if handler was removed, <c>false</c> otherwise.</returns> | |
/// <param name="handler">The handler.</param> | |
/// <typeparam name="T">The type that this handler will stop listening for</typeparam> | |
public bool RemoveHandler<T>(Action<T> handler) | |
{ | |
if (null == handler) | |
{ | |
throw new ArgumentNullException(nameof(handler)); | |
} | |
var handlerSet = GetOrCreateHandlerSet<T>(); | |
return handlerSet.Remove(handler); | |
} | |
/// <summary> | |
/// Dispatches a message to any handlers that need it | |
/// </summary> | |
/// <param name="arg">The message itself.</param> | |
/// <typeparam name="T">The message being sent to any handlers that need it.</typeparam> | |
public void Dispatch<T>(T arg) | |
{ | |
var handlerSet = GetOrCreateHandlerSet<T>(); | |
foreach (var handler in handlerSet) | |
{ | |
handler.Invoke(arg); | |
} | |
} | |
#if NET_4_6 | |
/// <summary> | |
/// Dispatches a message to any handles that need it in parallel | |
/// </summary> | |
/// <param name="arg">The message itself.</param> | |
/// <typeparam name="T">The message being sent to any hanadlers that need it.</typeparam> | |
public void DispatchParallel<T>(T arg) | |
{ | |
var handlerSet = GetOrCreateHandlerSet<T>(); | |
var tasks = new Task[handlerSet.Count]; | |
var index = 0; | |
foreach (var handler in handlerSet) | |
{ | |
tasks[index++] = Task.Run(() => handler.Invoke(arg)); | |
} | |
Task.WaitAll(tasks); | |
} | |
#endif | |
/// <summary> | |
/// Resets the handlers for a specific message type | |
/// </summary> | |
/// <typeparam name="T">The message type to reset handlers for.</typeparam> | |
public void Reset<T>() | |
{ | |
var hashSet = GetOrCreateHandlerSet<T>(); | |
hashSet.Clear(); | |
} | |
/// <summary> | |
/// Resets all handlers | |
/// </summary> | |
public void ResetAll() | |
{ | |
_handlers.Clear(); | |
} | |
/// <summary> | |
/// Gets the creates handler hash set in the dictionary. | |
/// </summary> | |
/// <returns>The handler set that was found or created.</returns> | |
/// <typeparam name="T">The type that the handler set is waiting for.</typeparam> | |
private HashSet<Action<T>> GetOrCreateHandlerSet<T>() | |
{ | |
var type = typeof(T); | |
HashSet<Action<T>> handlerSet; | |
object absHandler; | |
if (!_handlers.TryGetValue(type, out absHandler)) | |
{ | |
handlerSet = new HashSet<Action<T>>(); | |
_handlers[type] = handlerSet; | |
} else { | |
handlerSet = absHandler as HashSet<Action<T>>; | |
} | |
return handlerSet; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using NUnit.Framework; | |
using System; | |
public class EventManagerTests | |
{ | |
private readonly IEventManager _eventManager = new EventManager(); | |
[SetUp] | |
public void SetUp() | |
{ | |
_eventManager.ResetAll(); | |
} | |
[Test] | |
public void AddHandler_ShouldSucceed_WhenAddedOnce() | |
{ | |
// Arrange | |
Action<string> handler = (str) => { }; | |
// Act | |
var added = _eventManager.AddHandler(handler); | |
// Assert | |
Assert.IsTrue(added); | |
} | |
[Test] | |
public void AddHandler_ShouldFail_WhenAddedMoreThanOnce() | |
{ | |
// Arrange | |
Action<string> handler = (str) => { }; | |
// Act | |
var added1 = _eventManager.AddHandler(handler); | |
var added2 = _eventManager.AddHandler(handler); | |
// Assert | |
Assert.IsTrue(added1); | |
Assert.IsFalse(added2); | |
} | |
[Test] | |
public void RemoveHandler_ShouldSucceed_WhenRemovingAddedHandler() | |
{ | |
// Arrange | |
Action<string> handler = (str) => { }; | |
// Act | |
_eventManager.AddHandler(handler); | |
var removed = _eventManager.RemoveHandler(handler); | |
// Assert | |
Assert.IsTrue(removed); | |
} | |
[Test] | |
public void RemoveHandler_ShouldFail_WhenRemovingUnaddedHandler() | |
{ | |
// Arrange | |
Action<string> handler = (str) => { }; | |
// Act | |
var removed = _eventManager.RemoveHandler(handler); | |
// Assert | |
Assert.IsFalse(removed); | |
} | |
[Test] | |
public void Dispatch_ShouldKickOffHandler_WhenDispatching() | |
{ | |
// Arrange | |
var success = false; | |
Action<string> handler = (str) => { success = true; }; | |
// Act | |
_eventManager.AddHandler(handler); | |
_eventManager.Dispatch(""); | |
// Assert | |
Assert.IsTrue(success); | |
} | |
[Test] | |
public void Dispatch_ShouldNotKickOffHandler_WhenDispatchingDifferentType() | |
{ | |
// Arrange | |
var success = false; | |
Action<string> handler = (str) => { success = true; }; | |
// Act | |
_eventManager.AddHandler(handler); | |
_eventManager.Dispatch(true); | |
// Assert | |
Assert.IsFalse(success); | |
} | |
#if NET_4_6 | |
[Test] | |
public void DispatchParallel_ShouldKickOffHandler_WhenDispatching() | |
{ | |
// Arrange | |
var success = false; | |
Action<string> handler = (str) => { success = true; }; | |
// Act | |
_eventManager.AddHandler(handler); | |
_eventManager.DispatchParallel(""); | |
// Assert | |
Assert.IsTrue(success); | |
} | |
[Test] | |
public void DispatchParallel_ShouldNotKickOffHandler_WhenDispatchingDifferentType() | |
{ | |
// Arrange | |
var success = false; | |
Action<string> handler = (str) => { success = true; }; | |
// Act | |
_eventManager.AddHandler(handler); | |
_eventManager.DispatchParallel(true); | |
// Assert | |
Assert.IsFalse(success); | |
} | |
#endif | |
[Test] | |
public void Reset_ShouldResetOnlySpecificHandler_WhenResetting() | |
{ | |
// Arrange | |
var called = false; | |
Action<string> handler = (str) => { called = true; }; | |
// Act | |
_eventManager.AddHandler(handler); | |
_eventManager.Reset<string>(); | |
_eventManager.Dispatch(""); | |
// Assert | |
Assert.IsFalse(called); | |
} | |
[Test] | |
public void ResetAll_ShouldResetAllHandlers_WhenResetting() | |
{ | |
// Arrange | |
var called = false; | |
Action<string> handler1 = (str) => { called = true; }; | |
Action<bool> handler2 = (val) => { called = true; }; | |
// Act | |
_eventManager.AddHandler(handler1); | |
_eventManager.AddHandler(handler2); | |
_eventManager.ResetAll(); | |
_eventManager.Dispatch(""); | |
_eventManager.Dispatch(true); | |
// Assert | |
Assert.IsFalse(called); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
/// <summary> | |
/// Event manager interface | |
/// </summary> | |
public interface IEventManager | |
{ | |
/// <summary> | |
/// Adds a handler | |
/// </summary> | |
/// <returns><c>true</c>, if handler was added, <c>false</c> otherwise.</returns> | |
/// <param name="handler">The handler.</param> | |
/// <typeparam name="T">The type that this handler is listening for</typeparam> | |
bool AddHandler<T>(Action<T> handler); | |
/// <summary> | |
/// Removes a handler. | |
/// </summary> | |
/// <returns><c>true</c>, if handler was removed, <c>false</c> otherwise.</returns> | |
/// <param name="handler">The handler.</param> | |
/// <typeparam name="T">The type that this handler will stop listening for</typeparam> | |
bool RemoveHandler<T>(Action<T> handler); | |
/// <summary> | |
/// Dispatches a message to any handlers that need it | |
/// </summary> | |
/// <param name="arg">The message itself.</param> | |
/// <typeparam name="T">The message being sent to any handlers that need it.</typeparam> | |
void Dispatch<T>(T arg); | |
#if NET_4_6 | |
/// <summary> | |
/// Dispatches a message to any handles that need it in parallel | |
/// </summary> | |
/// <param name="arg">The message itself.</param> | |
/// <typeparam name="T">The message being sent to any hanadlers that need it.</typeparam> | |
void DispatchParallel<T>(T arg); | |
#endif | |
/// <summary> | |
/// Resets the handlers for a specific message type | |
/// </summary> | |
/// <typeparam name="T">The message type to reset handlers for.</typeparam> | |
void Reset<T>(); | |
/// <summary> | |
/// Resets all handlers | |
/// </summary> | |
void ResetAll(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment