--- source_files: - Common/DTS.Common.Core/ServiceManager/IServicePublishedEvent.cs - Common/DTS.Common.Core/ServiceManager/ServicePublishedEvent.cs - Common/DTS.Common.Core/ServiceManager/ServiceManager.cs generated_at: "2026-04-16T11:43:09.898125+00:00" model: "zai-org/GLM-5-FP8" schema_version: 1 sha256: "a01f75e5b963dd9f" --- # Documentation: DTS.Common.Core.ServiceManager ## 1. Purpose This module implements a service locator pattern via a static `ServiceManager` class. It allows components to publish implementations of interfaces (services) into a global container and retrieve them elsewhere without direct coupling to the implementation. It acts as a runtime registry for singleton services, supporting publication, retrieval, existence checks, and un-publication, while broadcasting state changes via an event system. ## 2. Public Interface ### `IServicePublishedEvent` (Interface) Defines the contract for events fired when a service state changes. * `Type ServiceType { get; }` — Gets the type of the service being published or unpublished. * `bool IsPublished { get; }` — Returns `true` if the service is being published; `false` if it is being unpublished. ### `ServicePublishedEvent` (Class) Concrete implementation of `IServicePublishedEvent`. * `Type ServiceType { get; internal set; }` — The service type. The setter is `internal`. * `bool IsPublished { get; internal set; }` — The publication state. The setter is `internal`. ### `ServiceManager` (Static Class) The static gateway for managing service registration. * `public static void Publish(T item) where T : class` * Registers a service implementation `item` under the interface type `T`. * Throws `ArgumentException` if `T` is already registered. * `public static void Publish(object item, IEnumerable interfaceList, bool skipPublishedInterfaces)` * Registers a single object `item` as the implementation for multiple interfaces defined in `interfaceList`. * If `skipPublishedInterfaces` is `false`, throws `ArgumentException` if any interface in the list is already registered. * If `skipPublishedInterfaces` is `true`, silently skips already registered interfaces. * `public static bool Exists() where T : class` * Returns `true` if a service of interface type `T` is currently registered; otherwise `false`. * `public static bool Exists(Type t)` * Non-generic overload. Returns `true` if the specified `Type t` is registered; otherwise `false`. * `public static T Get() where T : class` * Retrieves the registered service implementation for interface type `T`. * Throws `ArgumentException` if `T` has not been published. * `public static void Clear() where T : class` * Un-registers the service for interface type `T`. Fires an "unpublished" event. * `public static void Clear(IEnumerable interfaceList)` * Un-registers all services for the types specified in `interfaceList`. Fires "unpublished" events for each removed service. ## 3. Invariants * **Uniqueness:** The `ServiceManager` enforces a one-to-one mapping between a `Type` and a service instance. A `Type` cannot be published twice unless the previous instance is cleared or the batch publish method is used with `skipPublishedInterfaces` set to `true`. * **Reference Types Only:** All generic methods (`Publish`, `Exists`, `Get`, `Clear`) constrain the type parameter `T` to `class`. * **Event Ordering:** When clearing a service, the `IServicePublishedEvent` (with `IsPublished = false`) is fired **before** the service is removed from the internal dictionary. * **Exception Consistency:** Both `Publish` and `Get` throw `ArgumentException` (not a custom exception type) for invalid states (already exists / not found). ## 4. Dependencies * **Dependencies (Internal):** * `ServiceManager` depends on `ServicePublishedEvent` to create event payloads. * `ServicePublishedEvent` depends on `IServicePublishedEvent`. * **Dependencies (External):** * `ServiceManager` depends on `EventManager.EventManager`. The private method `SendServicePublishedEvent` calls `EventManager.EventManager.Publish(...)`. The location/assembly of `EventManager` is not defined in the provided source but is required for this module to compile and run. * **Standard Libraries:** `System`, `System.Collections.Generic`. ## 5. Gotchas * **Thread Safety:** The internal storage `Dictionary Services` uses standard `System.Collections.Generic.Dictionary`. There are no locks or synchronization mechanisms in `ServiceManager`. This module is **not thread-safe**. Concurrent calls to `Publish`, `Get`, or `Clear` may result in race conditions or corruption. * **Event Manager Coupling:** The `ServiceManager` is tightly coupled to a specific `EventManager.EventManager` class. If that event manager is not initialized or accessible, the `Publish` and `Clear` methods will fail at runtime when attempting to broadcast events. * **Silent Failures in Batch Publish:** When calling `Publish(object, IEnumerable, bool)` with `skipPublishedInterfaces` set to `true`, the method will silently ignore interfaces that are already registered. This could lead to stale service instances remaining active if the caller assumed the new `item` would replace them. * **Clear Event Timing:** Because the "unpublished" event fires before the item is removed from the dictionary, an event subscriber handling `IServicePublishedEvent` with `IsPublished == false` could technically still call `ServiceManager.Exists(type)` and receive `true` inside their event handler.