This commit is contained in:
2026-04-17 14:55:32 -04:00
commit bc3ac1d4c9
18017 changed files with 4371742 additions and 0 deletions

View File

@@ -0,0 +1,96 @@
---
source_files:
- DataPRO/DataPRO.Core/EventManager/EventManager.cs
generated_at: "2026-04-16T04:27:50.546850+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "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.