Tagging interface for event handlers

Support events in the TorchAPI
Static registry, non-static registration methods.
Support unregister by assembly.
This commit is contained in:
Westin Miller
2017-10-09 00:42:21 -07:00
parent 716e6cbc04
commit 013dc43c2f
8 changed files with 130 additions and 45 deletions

View File

@@ -1,10 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Torch.Managers.EventManager
namespace Torch.API.Managers.Event
{
/// <summary>
/// Attribute indicating that a method should be invoked when the event occurs.

View File

@@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Torch.Managers.EventManager
namespace Torch.API.Managers.Event
{
public interface IEvent
{

View File

@@ -0,0 +1,9 @@
namespace Torch.API.Managers.Event
{
/// <summary>
/// Interface used to tag an event handler. This does <b>not</b> register it with the event manager.
/// </summary>
public interface IEventHandler
{
}
}

View File

@@ -0,0 +1,27 @@
using System.Runtime.CompilerServices;
namespace Torch.API.Managers.Event
{
/// <summary>
/// Manager class responsible for registration of event handlers.
/// </summary>
public interface IEventManager
{
/// <summary>
/// Registers all event handler methods contained in the given instance
/// </summary>
/// <param name="handler">Instance to register</param>
/// <returns><b>true</b> if added, <b>false</b> otherwise</returns>
[MethodImpl(MethodImplOptions.NoInlining)]
bool RegisterHandler(IEventHandler handler);
/// <summary>
/// Unregisters all event handler methods contained in the given instance
/// </summary>
/// <param name="handler">Instance to unregister</param>
/// <returns><b>true</b> if removed, <b>false</b> otherwise</returns>
[MethodImpl(MethodImplOptions.NoInlining)]
bool UnregisterHandler(IEventHandler handler);
}
}

View File

@@ -1,13 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Torch.API.Managers.Event;
using Torch.Managers.EventManager;
namespace Torch.Managers.EventManager
namespace Torch.Managers.Event
{
/// <summary>
/// Represents an ordered list of callbacks.
@@ -49,7 +48,7 @@ namespace Torch.Managers.EventManager
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
/// <inheritdoc/>
public void AddHandler(MethodInfo method, object instance)
public void AddHandler(MethodInfo method, IEventHandler instance)
{
try
{
@@ -64,7 +63,7 @@ namespace Torch.Managers.EventManager
}
/// <inheritdoc/>
public int RemoveHandlers(object instance)
public int RemoveHandlers(IEventHandler instance)
{
try
{

View File

@@ -3,23 +3,21 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using NLog;
using Torch.API;
using Torch.API.Managers;
using VRage.Game.ModAPI;
using Torch.API.Managers.Event;
using Torch.Managers.EventManager;
namespace Torch.Managers.EventManager
namespace Torch.Managers.Event
{
/// <summary>
/// Manager class responsible for managing registration and dispatching of events.
/// </summary>
public class EventManager : Manager
public class EventManager : Manager, IEventManager
{
private static readonly Logger _log = LogManager.GetCurrentClassLogger();
private static Dictionary<Type, IEventList> _eventLists = new Dictionary<Type, IEventList>();
private static readonly Dictionary<Type, IEventList> _eventLists = new Dictionary<Type, IEventList>();
static EventManager()
{
@@ -41,11 +39,7 @@ namespace Torch.Managers.EventManager
}
}
/// <summary>
/// Finds all event handlers in the given type, and its base types
/// </summary>
/// <param name="exploreType">Type to explore</param>
/// <returns>All event handlers</returns>
/// <inheritdoc/>
private static IEnumerable<MethodInfo> EventHandlers(Type exploreType)
{
IEnumerable<MethodInfo> enumerable = exploreType.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)
@@ -62,11 +56,8 @@ namespace Torch.Managers.EventManager
return exploreType.BaseType != null ? enumerable.Concat(EventHandlers(exploreType.BaseType)) : enumerable;
}
/// <summary>
/// Registers all handlers the given instance owns.
/// </summary>
/// <param name="instance">Instance to register handlers from</param>
private static void RegisterHandler(object instance)
/// <inheritdoc/>
private static void RegisterHandlerInternal(IEventHandler instance)
{
foreach (MethodInfo handler in EventHandlers(instance.GetType()))
{
@@ -96,15 +87,86 @@ namespace Torch.Managers.EventManager
/// Unregisters all handlers owned by the given instance
/// </summary>
/// <param name="instance">Instance</param>
private static void UnregisterHandlers(object instance)
private static void UnregisterHandlerInternal(IEventHandler instance)
{
foreach (IEventList list in _eventLists.Values)
list.RemoveHandlers(instance);
}
private Dictionary<Assembly, HashSet<IEventHandler>> _registeredHandlers = new Dictionary<Assembly, HashSet<IEventHandler>>();
/// <inheritdoc/>
public EventManager(ITorchBase torchInstance) : base(torchInstance)
{
}
/// <summary>
/// Registers all event handler methods contained in the given instance
/// </summary>
/// <param name="handler">Instance to register</param>
/// <returns><b>true</b> if added, <b>false</b> otherwise</returns>
[MethodImpl(MethodImplOptions.NoInlining)]
public bool RegisterHandler(IEventHandler handler)
{
Assembly caller = Assembly.GetCallingAssembly();
lock (_registeredHandlers)
{
if (!_registeredHandlers.TryGetValue(caller, out HashSet<IEventHandler> handlers))
_registeredHandlers.Add(caller, handlers = new HashSet<IEventHandler>());
if (handlers.Add(handler))
{
RegisterHandlerInternal(handler);
return true;
}
return false;
}
}
/// <summary>
/// Unregisters all event handler methods contained in the given instance
/// </summary>
/// <param name="handler">Instance to unregister</param>
/// <returns><b>true</b> if removed, <b>false</b> otherwise</returns>
[MethodImpl(MethodImplOptions.NoInlining)]
public bool UnregisterHandler(IEventHandler handler)
{
Assembly caller = Assembly.GetCallingAssembly();
lock (_registeredHandlers)
{
if (!_registeredHandlers.TryGetValue(caller, out HashSet<IEventHandler> handlers))
return false;
if (handlers.Remove(handler))
{
UnregisterHandlerInternal(handler);
return true;
}
return false;
}
}
/// <summary>
/// Unregisters all handlers owned by the given assembly.
/// </summary>
/// <param name="asm">Assembly to unregister</param>
/// <param name="callback">Optional callback invoked for every registered handler in the assembly. Ignored if null</param>
/// <returns>the number of handlers that were unregistered</returns>
internal int UnregisterAllHandlers(Assembly asm, Func<IEventHandler> callback = null)
{
lock (_registeredHandlers)
{
if (!_registeredHandlers.TryGetValue(asm, out HashSet<IEventHandler> handlers))
return 0;
foreach (IEventHandler k in handlers)
{
callback?.Invoke();
UnregisterHandlerInternal(k);
}
int count = handlers.Count;
handlers.Clear();
_registeredHandlers.Remove(asm);
return count;
}
}
}
}

View File

@@ -6,6 +6,8 @@ using System.Text;
using System.Threading.Tasks;
using Sandbox.Game.Entities;
using Sandbox.Game.Entities.Blocks;
using Torch.API.Managers.Event;
using Torch.Managers.Event;
using Torch.Managers.PatchManager;
using Torch.Utils;

View File

@@ -1,11 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using Torch.API.Managers.Event;
namespace Torch.Managers.EventManager
namespace Torch.Managers.Event
{
/// <summary>
/// Represents the interface for adding and removing from an ordered list of callbacks.
@@ -17,13 +13,13 @@ namespace Torch.Managers.EventManager
/// </summary>
/// <param name="method">Handler method</param>
/// <param name="instance">Instance to invoke the handler on</param>
void AddHandler(MethodInfo method, object instance);
void AddHandler(MethodInfo method, IEventHandler instance);
/// <summary>
/// Removes all event handlers invoked on the given instance.
/// </summary>
/// <param name="instance">Instance to remove event handlers for</param>
/// <returns>The number of event handlers removed</returns>
int RemoveHandlers(object instance);
int RemoveHandlers(IEventHandler instance);
}
}