Files
2026-04-17 14:55:32 -04:00

194 lines
6.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Reflection;
namespace DTS.Common.Core.EventManager
{
/// <summary>
/// Delegate used by event listeners
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="item"></param>
public delegate void SubscriberCallbackDelegate<in T>(T item) where T : class;
public delegate void DiagnosticCallbackDelegate(EventDiagnosticType eventType, Type t, object eventData, string listener);
/// <summary>
/// Allows components to publish events without knowing who is listening
/// </summary>
public static class EventManager
{
/// <summary>
/// Tracks listeners
/// </summary>
private static readonly Dictionary<Type, List<object>> SubscriberList = new Dictionary<Type, List<object>>();
/// <summary>
/// Tracks diagnostic listeners
/// </summary>
private static readonly List<DiagnosticCallbackDelegate> DiagnosticList = new List<DiagnosticCallbackDelegate>();
/// <summary>
/// Publish an event
/// </summary>
/// <typeparam name="T">type of event</typeparam>
/// <param name="eventData">event listener</param>
public static void Publish<T>(T eventData) where T : class
{
if (!SubscriberList.ContainsKey(typeof(T))) return;
var listeners = SubscriberList[typeof(T)];
foreach (var listener in listeners)
{
var metaData = listener as EventMetaData<T>;
if (metaData == null) continue;
var triggerCallback = true;
if (metaData.EventFilter != null)
{
triggerCallback = metaData.EventFilter(eventData);
}
if (triggerCallback)
{
metaData.Callback(eventData);
}
SendDiagnosticEvent(EventDiagnosticType.PublishEvent, typeof(T), eventData, metaData.EventFilter?.Method);
}
}
/// <summary>
/// Subscribe to an event
/// </summary>
/// <typeparam name="T">type of event</typeparam>
/// <param name="listener">event listener</param>
public static void Subscribe<T>(SubscriberCallbackDelegate<T> listener) where T : class
{
Subscribe(listener, null);
}
/// <summary>
/// Subscribe to an event
/// </summary>
/// <typeparam name="T">type of event</typeparam>
/// <param name="listener">event listener</param>
/// <param name="eventFilter">predicate to filter events sent to event listener</param>
public static void Subscribe<T>(SubscriberCallbackDelegate<T> listener, Predicate<T> eventFilter) where T : class
{
if (!SubscriberList.ContainsKey(typeof(T)))
{
SubscriberList.Add(typeof(T), new List<object>());
}
var listeners = SubscriberList[typeof(T)];
var metaData = new EventMetaData<T> { Callback = listener, EventFilter = eventFilter };
listeners.Add(metaData);
SendDiagnosticEvent(EventDiagnosticType.AddListener, typeof(T), null, listener.Method);
}
/// <summary>
/// Allows a subscriber to unsubscribe
/// </summary>
/// <typeparam name="T">type of event</typeparam>
/// <param name="listener">event listener</param>
public static void UnSubscribe<T>(SubscriberCallbackDelegate<T> listener) where T : class
{
if (!SubscriberList.ContainsKey(typeof(T))) return;
var listeners = SubscriberList[typeof(T)];
listeners.RemoveAll(p =>
{
return p is EventMetaData<T> eventMetaData && eventMetaData.Callback == listener;
});
SendDiagnosticEvent(EventDiagnosticType.RemoveListener, typeof(T), null, listener.Method);
}
/// <summary>
/// Clears all listeners
/// </summary>
public static void Clear()
{
SubscriberList.Clear();
SendDiagnosticEvent(EventDiagnosticType.RemoveListener, null, null, null);
}
/// <summary>
/// Add diagnostic listener
/// </summary>
/// <param name="listener">event listener</param>
public static void SubscribeToDiagnosticEvents(DiagnosticCallbackDelegate listener)
{
DiagnosticList.Add(listener);
SendDiagnosticEvent(EventDiagnosticType.AddListenerDiagnostic, null, null, listener.Method);
}
/// <summary>
/// Clear diagnostic event
/// </summary>
/// <param name="listener">listener to unsubscribe</param>
public static void UnSubscribeToDiagnosticEvents(DiagnosticCallbackDelegate listener)
{
DiagnosticList.RemoveAll(p => p == listener);
SendDiagnosticEvent(EventDiagnosticType.RemoveListenerDiagnostic, null, null, listener.Method);
}
/// <summary>
/// Clear all diagnostic events
/// </summary>
public static void ClearDiagnosticEvents()
{
DiagnosticList.Clear();
SendDiagnosticEvent(EventDiagnosticType.RemoveListenerDiagnostic, null, null, null);
}
/// <summary>
/// Sends a diagnostic event
/// </summary>
/// <param name="diagnosticEventType"></param>
/// <param name="eventType"></param>
/// <param name="eventData"></param>
/// <param name="listenerMethod"></param>
private static void SendDiagnosticEvent(EventDiagnosticType diagnosticEventType, Type eventType, object eventData, MemberInfo listenerMethod)
{
foreach (var diagnosticEvent in DiagnosticList)
{
string listener = null;
if (listenerMethod != null && listenerMethod.DeclaringType != null)
{
listener = $"{listenerMethod.DeclaringType.FullName}.{listenerMethod.Name} , {listenerMethod.DeclaringType.Assembly.FullName}";
}
diagnosticEvent(diagnosticEventType, eventType, eventData, listener);
}
}
}
public enum EventDiagnosticType
{
AddListener = 0,
AddListenerDiagnostic = 1,
PublishEvent = 2,
RemoveListenerDiagnostic = 3,
RemoveListener = 4
}
internal class EventMetaData<T> where T : class
{
public Predicate<T> EventFilter { get; set; }
public SubscriberCallbackDelegate<T> Callback { get; set; }
}
}