TechbloxModdingAPI/TechbloxModdingAPI/Utility/WrappedHandler.cs

59 lines
No EOL
2 KiB
C#

using System;
using System.Collections.Generic;
using TechbloxModdingAPI.Events;
namespace TechbloxModdingAPI.Utility
{
/// <summary>
/// Wraps the event handler in a try-catch block to avoid propagating exceptions.
/// </summary>
/// <typeparam name="T">The event arguments type</typeparam>
public struct WrappedHandler<T>
{
private EventHandler<T> eventHandler;
/// <summary>
/// Store wrappers so we can unregister them properly
/// </summary>
private static Dictionary<EventHandler<T>, EventHandler<T>> wrappers =
new Dictionary<EventHandler<T>, EventHandler<T>>();
public static WrappedHandler<T> operator +(WrappedHandler<T> original, EventHandler<T> added)
{
EventHandler<T> wrapped = (sender, e) =>
{
try
{
added(sender, e);
}
catch (Exception e1)
{
EventRuntimeException wrappedException =
new EventRuntimeException($"EventHandler with arg type {typeof(T).Name} threw an exception",
e1);
Logging.LogWarning(wrappedException.ToString());
}
};
if (wrappers.ContainsKey(added))
{
original.eventHandler -= wrapped;
wrappers.Remove(added);
}
wrappers.Add(added, wrapped);
return new WrappedHandler<T> { eventHandler = original.eventHandler + wrapped };
}
public static WrappedHandler<T> operator -(WrappedHandler<T> original, EventHandler<T> removed)
{
if (!wrappers.TryGetValue(removed, out var wrapped)) return original;
wrappers.Remove(removed);
return new WrappedHandler<T> { eventHandler = original.eventHandler - wrapped };
}
public void Invoke(object sender, T args)
{
eventHandler?.Invoke(sender, args);
}
}
}