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

6.5 KiB

source_files, generated_at, model, schema_version, sha256
source_files generated_at model schema_version sha256
DataPRO/DataPRO.Core/EventManager/EventManager.cs
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 type T.

  • delegate void DiagnosticCallbackDelegate(EventDiagnosticType eventType, Type t, object eventData, string listener)
    Signature for diagnostic event callbacks. Reports internal EventManager operations (e.g., add/remove listener, publish event) with context:

    • eventType: Kind of operation (EventDiagnosticType)
    • t: Event type being subscribed/published
    • eventData: Event payload (may be null for 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 type T. Invokes all registered listeners for T, applying any per-listener filter. Skips if no listeners exist for T. 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 type T. Internally calls Subscribe<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 if eventFilter(eventData) returns true. Registers metadata (EventMetaData<T>) and sends a diagnostic event.

  • static void UnSubscribe<T>(SubscriberCallbackDelegate<T> listener) where T : class
    Removes all subscriptions of listener for events of type T. 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> and Subscribe<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 one SendDiagnosticEvent call.
  • No Thread Safety: The module is not thread-safe. Concurrent access to SubscriberList or DiagnosticList may cause corruption (no locking is present).
  • Diagnostic Listener Isolation: Diagnostic listeners do not receive diagnostics about their own registration/unregistration (e.g., SubscribeToDiagnosticEvents triggers a diagnostic, but the newly added listener does not receive it).

4. Dependencies

  • Internal Dependencies:

    • System namespace (System.Collections.Generic, System.Reflection, System)
    • EventDiagnosticType enum (defined in same file)
    • EventMetaData<T> class (defined in same file, internal scope)
    • SubscriberCallbackDelegate<T> and DiagnosticCallbackDelegate delegates (defined in same file)
  • External Dependencies:

    • None beyond standard .NET libraries (no external NuGet packages or framework dependencies beyond mscorlib).
  • Depended Upon:

    • Any component in the DataPro.Core namespace (or referencing the assembly) may use EventManager to publish/subscribe to events.
    • Diagnostic consumers (e.g., logging, telemetry, debugging tools) subscribe via SubscribeToDiagnosticEvents.

5. Gotchas

  • eventData in DiagnosticCallbackDelegate may be null: For subscription/unsubscription/diagnostic registration events, eventData is null. Diagnostic listeners must handle this.
  • listener string may be null: If listenerMethod.DeclaringType is null (e.g., static method in anonymous type), the listener string passed to the diagnostic callback is null.
  • Clear() is global and destructive: Removes all subscriptions across all event types—no selective clearing is supported.
  • No deduplication on subscription: Calling Subscribe twice with the same listener and filter adds two entries. Unsubscribing once removes only one entry (per RemoveAll logic). 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.Method as 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 EventManager operations. 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.