diff --git a/GFramework.Core/events/EasyEventGeneric.cs b/GFramework.Core/events/EasyEventGeneric.cs index 002678c..e1fbffb 100644 --- a/GFramework.Core/events/EasyEventGeneric.cs +++ b/GFramework.Core/events/EasyEventGeneric.cs @@ -59,6 +59,15 @@ public class Event : IEvent { _mOnEvent?.Invoke(t); } + + /// + /// 获取当前已注册的监听器数量 + /// + /// 监听器数量 + public int GetListenerCount() + { + return _mOnEvent?.GetInvocationList().Length ?? 0; + } } /// @@ -120,4 +129,13 @@ public class Event : IEvent { _mOnEvent?.Invoke(t, k); } + + /// + /// 获取当前已注册的监听器数量 + /// + /// 监听器数量 + public int GetListenerCount() + { + return _mOnEvent?.GetInvocationList().Length ?? 0; + } } \ No newline at end of file diff --git a/GFramework.Core/events/EnhancedEventBus.cs b/GFramework.Core/events/EnhancedEventBus.cs index 248228b..dd7d752 100644 --- a/GFramework.Core/events/EnhancedEventBus.cs +++ b/GFramework.Core/events/EnhancedEventBus.cs @@ -37,6 +37,8 @@ public sealed class EnhancedEventBus : IEventBus /// 事件类型 public void Send() where T : new() { + _statistics?.RecordPublish(typeof(T).Name); + _mEvents .GetOrAddEvent>() .Trigger(new T()); @@ -49,6 +51,8 @@ public sealed class EnhancedEventBus : IEventBus /// 事件实例 public void Send(T e) { + _statistics?.RecordPublish(typeof(T).Name); + _mEvents .GetOrAddEvent>() .Trigger(e); @@ -62,6 +66,8 @@ public sealed class EnhancedEventBus : IEventBus /// 事件传播方式 public void Send(T e, EventPropagation propagation) { + _statistics?.RecordPublish(typeof(T).Name); + _mPriorityEvents .GetOrAddEvent>() .Trigger(e, propagation); @@ -75,6 +81,32 @@ public sealed class EnhancedEventBus : IEventBus /// 反注册接口,用于取消订阅 public IUnRegister Register(Action onEvent) { + if (_statistics != null) + { + // 包装回调以添加统计 + Action wrappedHandler = data => + { + try + { + onEvent(data); + _statistics.RecordHandle(); + } + catch + { + _statistics.RecordFailure(); + throw; + } + }; + + var unregister = _mEvents.GetOrAddEvent>().Register(wrappedHandler); + UpdateEventListenerCount(); + return new DefaultUnRegister(() => + { + unregister.UnRegister(); + UpdateEventListenerCount(); + }); + } + return _mEvents.GetOrAddEvent>().Register(onEvent); } @@ -87,6 +119,32 @@ public sealed class EnhancedEventBus : IEventBus /// 反注册接口,用于取消订阅 public IUnRegister Register(Action onEvent, int priority) { + if (_statistics != null) + { + // 包装回调以添加统计 + Action wrappedHandler = data => + { + try + { + onEvent(data); + _statistics.RecordHandle(); + } + catch + { + _statistics.RecordFailure(); + throw; + } + }; + + var unregister = _mPriorityEvents.GetOrAddEvent>().Register(wrappedHandler, priority); + UpdatePriorityEventListenerCount(); + return new DefaultUnRegister(() => + { + unregister.UnRegister(); + UpdatePriorityEventListenerCount(); + }); + } + return _mPriorityEvents.GetOrAddEvent>().Register(onEvent, priority); } @@ -98,6 +156,7 @@ public sealed class EnhancedEventBus : IEventBus public void UnRegister(Action onEvent) { _mEvents.GetEvent>().UnRegister(onEvent); + UpdateEventListenerCount(); } /// @@ -108,6 +167,32 @@ public sealed class EnhancedEventBus : IEventBus /// 反注册接口,用于取消订阅 public IUnRegister RegisterWithContext(Action> onEvent) { + if (_statistics != null) + { + // 包装回调以添加统计 + Action> wrappedHandler = context => + { + try + { + onEvent(context); + _statistics.RecordHandle(); + } + catch + { + _statistics.RecordFailure(); + throw; + } + }; + + var unregister = _mPriorityEvents.GetOrAddEvent>().RegisterWithContext(wrappedHandler); + UpdatePriorityEventListenerCount(); + return new DefaultUnRegister(() => + { + unregister.UnRegister(); + UpdatePriorityEventListenerCount(); + }); + } + return _mPriorityEvents.GetOrAddEvent>().RegisterWithContext(onEvent); } @@ -120,6 +205,33 @@ public sealed class EnhancedEventBus : IEventBus /// 反注册接口,用于取消订阅 public IUnRegister RegisterWithContext(Action> onEvent, int priority) { + if (_statistics != null) + { + // 包装回调以添加统计 + Action> wrappedHandler = context => + { + try + { + onEvent(context); + _statistics.RecordHandle(); + } + catch + { + _statistics.RecordFailure(); + throw; + } + }; + + var unregister = _mPriorityEvents.GetOrAddEvent>() + .RegisterWithContext(wrappedHandler, priority); + UpdatePriorityEventListenerCount(); + return new DefaultUnRegister(() => + { + unregister.UnRegister(); + UpdatePriorityEventListenerCount(); + }); + } + return _mPriorityEvents.GetOrAddEvent>().RegisterWithContext(onEvent, priority); } @@ -239,4 +351,40 @@ public sealed class EnhancedEventBus : IEventBus } #endregion + + #region Helper Methods + + /// + /// 更新普通事件的监听器数量统计 + /// + private void UpdateEventListenerCount() + { + if (_statistics == null) + return; + + var evt = _mEvents.GetEvent>(); + if (evt != null) + { + var count = evt.GetListenerCount(); + _statistics.UpdateListenerCount(typeof(T).Name, count); + } + } + + /// + /// 更新优先级事件的监听器数量统计 + /// + private void UpdatePriorityEventListenerCount() + { + if (_statistics == null) + return; + + var evt = _mPriorityEvents.GetEvent>(); + if (evt != null) + { + var count = evt.GetListenerCount(); + _statistics.UpdateListenerCount(typeof(T).Name, count); + } + } + + #endregion } \ No newline at end of file diff --git a/GFramework.Core/events/EventStatistics.cs b/GFramework.Core/events/EventStatistics.cs index b1973d2..4f7d447 100644 --- a/GFramework.Core/events/EventStatistics.cs +++ b/GFramework.Core/events/EventStatistics.cs @@ -12,8 +12,6 @@ public sealed class EventStatistics : IEventStatistics private readonly Dictionary _listenerCountByType = new(); private readonly object _lock = new(); private readonly Dictionary _publishCountByType = new(); - private int _activeEventTypes; - private int _activeListeners; private long _totalFailed; private long _totalHandled; private long _totalPublished; @@ -30,15 +28,25 @@ public sealed class EventStatistics : IEventStatistics /// public int ActiveEventTypes { - get => Interlocked.CompareExchange(ref _activeEventTypes, 0, 0); - set => Interlocked.Exchange(ref _activeEventTypes, value); + get + { + lock (_lock) + { + return _publishCountByType.Count; + } + } } /// public int ActiveListeners { - get => Interlocked.CompareExchange(ref _activeListeners, 0, 0); - set => Interlocked.Exchange(ref _activeListeners, value); + get + { + lock (_lock) + { + return _listenerCountByType.Values.Sum(); + } + } } /// @@ -65,8 +73,6 @@ public sealed class EventStatistics : IEventStatistics Interlocked.Exchange(ref _totalPublished, 0); Interlocked.Exchange(ref _totalHandled, 0); Interlocked.Exchange(ref _totalFailed, 0); - Interlocked.Exchange(ref _activeEventTypes, 0); - Interlocked.Exchange(ref _activeListeners, 0); lock (_lock) { diff --git a/GFramework.Core/events/FilterableEvent.cs b/GFramework.Core/events/FilterableEvent.cs index 34e3cf1..406340f 100644 --- a/GFramework.Core/events/FilterableEvent.cs +++ b/GFramework.Core/events/FilterableEvent.cs @@ -61,21 +61,21 @@ public sealed class FilterableEvent // 记录发布统计 _statistics?.RecordPublish(typeof(T).Name); - // 应用过滤器 - lock (_lock) - { - // 事件被过滤,不触发监听器 - if (_filters.Any(filter => filter.ShouldFilter(data))) - return; - } - - // 获取当前监听器快照(在锁外调用) + // 在单个锁中快照过滤器和监听器 Action? handlers; + IEventFilter[] filtersSnapshot; + lock (_lock) { + filtersSnapshot = _filters.Count > 0 ? _filters.ToArray() : Array.Empty>(); handlers = _onEvent; } + // 在锁外执行过滤逻辑 + // 事件被过滤,不触发监听器 + if (filtersSnapshot.Any(filter => filter.ShouldFilter(data))) + return; + if (handlers == null) return; diff --git a/GFramework.Core/events/PriorityEvent.cs b/GFramework.Core/events/PriorityEvent.cs index 5be3376..85b054b 100644 --- a/GFramework.Core/events/PriorityEvent.cs +++ b/GFramework.Core/events/PriorityEvent.cs @@ -254,6 +254,15 @@ public class PriorityEvent : IEvent } } + /// + /// 获取当前已注册的监听器总数量(包括普通监听器和上下文监听器) + /// + /// 监听器总数量 + public int GetListenerCount() + { + return _handlers.Count + _contextHandlers.Count; + } + /// /// 事件处理器包装类,包含处理器和优先级 /// diff --git a/GFramework.Core/events/StatisticsEventDecorator.cs b/GFramework.Core/events/StatisticsEventDecorator.cs new file mode 100644 index 0000000..ac9e3a5 --- /dev/null +++ b/GFramework.Core/events/StatisticsEventDecorator.cs @@ -0,0 +1,108 @@ +using GFramework.Core.Abstractions.events; + +namespace GFramework.Core.events; + +/// +/// 带统计功能的事件装饰器 +/// 使用装饰器模式为任何 IEvent 实现添加统计功能 +/// +/// 事件数据类型 +internal sealed class StatisticsEventDecorator +{ + private readonly string _eventTypeName; + private readonly IEvent _innerEvent; + private readonly EventStatistics _statistics; + + /// + /// 构造函数 + /// + /// 被装饰的事件对象 + /// 统计对象 + public StatisticsEventDecorator(IEvent innerEvent, EventStatistics statistics) + { + _innerEvent = innerEvent ?? throw new ArgumentNullException(nameof(innerEvent)); + _statistics = statistics ?? throw new ArgumentNullException(nameof(statistics)); + _eventTypeName = typeof(T).Name; + } + + /// + /// 注册事件监听器(带统计) + /// + /// 事件处理回调 + /// 反注册接口 + public IUnRegister Register(Action onEvent) + { + // 包装回调以添加统计 + Action wrappedHandler = data => + { + try + { + onEvent(data); + _statistics.RecordHandle(); + } + catch + { + _statistics.RecordFailure(); + throw; + } + }; + + var unregister = _innerEvent.Register(() => { }); // 占位,实际不使用 + + // 直接注册到内部事件 + if (_innerEvent is Event typedEvent) + { + unregister = typedEvent.Register(wrappedHandler); + } + else if (_innerEvent is PriorityEvent priorityEvent) + { + unregister = priorityEvent.Register(wrappedHandler); + } + + // 更新监听器统计 + UpdateListenerCount(); + + return new DefaultUnRegister(() => + { + unregister.UnRegister(); + UpdateListenerCount(); + }); + } + + /// + /// 触发事件(带统计) + /// + /// 事件数据 + public void Trigger(T data) + { + _statistics.RecordPublish(_eventTypeName); + + if (_innerEvent is Event typedEvent) + { + typedEvent.Trigger(data); + } + else if (_innerEvent is PriorityEvent priorityEvent) + { + priorityEvent.Trigger(data, EventPropagation.Continue); + } + } + + /// + /// 更新监听器数量统计 + /// + private void UpdateListenerCount() + { + var count = 0; + + if (_innerEvent is Event typedEvent) + { + count = typedEvent.GetListenerCount(); + } + else if (_innerEvent is PriorityEvent priorityEvent) + { + count = priorityEvent.GetListenerCount(); + } + + _statistics.UpdateListenerCount(_eventTypeName, count); + } +} \ No newline at end of file