6.5 KiB
source_files, generated_at, model, schema_version, sha256
| source_files | generated_at | model | schema_version | sha256 | |
|---|---|---|---|---|---|
|
2026-04-16T04:27:50.546850+00:00 | Qwen/Qwen3-Coder-Next-FP8 | 1 | 563530faa0be756e |
EventManager
Documentation: EventManager Module
1. Purpose
The EventManager class provides a central, static event-publishing/subscribing mechanism that decouples event producers from consumers. It enables components to publish typed events (Publish<T>) and subscribe to them with optional filtering (Subscribe<T>), while maintaining a diagnostic logging capability for runtime introspection. This module exists to support loose coupling in the system, avoiding direct dependencies between event emitters and listeners, and to aid debugging and monitoring via diagnostic events.
2. Public Interface
-
delegate void SubscriberCallbackDelegate<in T>(T item) where T : class
Signature for event listener callbacks. Receives the event payload (item) of typeT. -
delegate void DiagnosticCallbackDelegate(EventDiagnosticType eventType, Type t, object eventData, string listener)
Signature for diagnostic event callbacks. Reports internalEventManageroperations (e.g., add/remove listener, publish event) with context:eventType: Kind of operation (EventDiagnosticType)t: Event type being subscribed/publishedeventData: Event payload (may benullfor subscription/unsubscription events)listener: Fully qualified method name and assembly (e.g.,"MyNamespace.MyClass.MyMethod, MyAssembly")
-
static void Publish<T>(T eventData) where T : class
Publishes an event of typeT. Invokes all registered listeners forT, applying any per-listener filter. Skips if no listeners exist forT. Sends a diagnostic event for each invocation. -
static void Subscribe<T>(SubscriberCallbackDelegate<T> listener) where T : class
Subscribes a listener (no filter) to events of typeT. Internally callsSubscribe<T>(listener, null). -
static void Subscribe<T>(SubscriberCallbackDelegate<T> listener, Predicate<T> eventFilter) where T : class
Subscribes a listener with an optional filter (eventFilter). The listener is invoked only ifeventFilter(eventData)returnstrue. Registers metadata (EventMetaData<T>) and sends a diagnostic event. -
static void UnSubscribe<T>(SubscriberCallbackDelegate<T> listener) where T : class
Removes all subscriptions oflistenerfor events of typeT. Sends a diagnostic event. -
static void Clear()
Removes all subscriptions for all event types. Sends a diagnostic event. -
static void SubscribeToDiagnosticEvents(DiagnosticCallbackDelegate listener)
Registers a diagnostic listener. Sends a diagnostic event reporting the addition. -
static void UnSubscribeToDiagnosticEvents(DiagnosticCallbackDelegate listener)
Removes a diagnostic listener. Sends a diagnostic event reporting the removal. -
static void ClearDiagnosticEvents()
Removes all diagnostic listeners. Sends a diagnostic event.
3. Invariants
- Type Safety: All subscriptions and publications are strictly typed via generics (
T). No type erasure occurs;Subscribe<int>andSubscribe<string>maintain separate listener lists. - Filter Semantics: Filters are per-subscription and evaluated at publish time. If
eventFilter == null, the listener is always invoked. - Listener Identity: Unsubscription is based on reference equality of the delegate (
listener). Two distinct delegates (even with identical implementation) are treated as different listeners. - Diagnostic Consistency: Every public mutation (
Subscribe,UnSubscribe,Publish,Clear, diagnostic subscription changes) triggers exactly oneSendDiagnosticEventcall. - No Thread Safety: The module is not thread-safe. Concurrent access to
SubscriberListorDiagnosticListmay cause corruption (no locking is present). - Diagnostic Listener Isolation: Diagnostic listeners do not receive diagnostics about their own registration/unregistration (e.g.,
SubscribeToDiagnosticEventstriggers a diagnostic, but the newly added listener does not receive it).
4. Dependencies
-
Internal Dependencies:
Systemnamespace (System.Collections.Generic,System.Reflection,System)EventDiagnosticTypeenum (defined in same file)EventMetaData<T>class (defined in same file,internalscope)SubscriberCallbackDelegate<T>andDiagnosticCallbackDelegatedelegates (defined in same file)
-
External Dependencies:
- None beyond standard .NET libraries (no external NuGet packages or framework dependencies beyond
mscorlib).
- None beyond standard .NET libraries (no external NuGet packages or framework dependencies beyond
-
Depended Upon:
- Any component in the
DataPro.Corenamespace (or referencing the assembly) may useEventManagerto publish/subscribe to events. - Diagnostic consumers (e.g., logging, telemetry, debugging tools) subscribe via
SubscribeToDiagnosticEvents.
- Any component in the
5. Gotchas
eventDatainDiagnosticCallbackDelegatemay benull: For subscription/unsubscription/diagnostic registration events,eventDataisnull. Diagnostic listeners must handle this.listenerstring may benull: IflistenerMethod.DeclaringTypeisnull(e.g., static method in anonymous type), thelistenerstring passed to the diagnostic callback isnull.Clear()is global and destructive: Removes all subscriptions across all event types—no selective clearing is supported.- No deduplication on subscription: Calling
Subscribetwice with the same listener and filter adds two entries. Unsubscribing once removes only one entry (perRemoveAlllogic). This may cause duplicate invocations if not managed carefully. - Filter method reference in diagnostics: When a filter is present, the diagnostic event reports
metaData.EventFilter.Methodas the listener method—not the callback method. This may be confusing if the filter and callback are defined in different methods. - No weak references: Listeners are held via strong references. If subscribers forget to
UnSubscribe, they may be kept alive indefinitely (memory leak risk). - Diagnostic events are synchronous and blocking: Each diagnostic callback is invoked synchronously during
EventManageroperations. Slow diagnostic handlers will delay event publishing/subscription. EventMetaData<T>is internal: Cannot be extended or inspected externally; behavior is fixed by the implementation.
None identified beyond the above.