Files

92 lines
5.9 KiB
Markdown
Raw Permalink Normal View History

2026-04-17 14:55:32 -04:00
---
source_files:
- Common/DTS.Common/ModuleCatalog/AggregateModuleCatalog.cs
generated_at: "2026-04-16T02:54:14.695851+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "7afb65b5d3f17781"
---
# ModuleCatalog
### **Purpose**
The `AggregateModuleCatalog` class serves as a composite wrapper around multiple `IModuleCatalog` instances, enabling modular module discovery and management across heterogeneous sources (e.g., configuration files, assemblies, or dynamic catalogs) within the Prism-based module loading framework. It consolidates module definitions from its constituent catalogs into a unified interface while delegating core operations—such as dependency resolution, initialization, and module enumeration—to the underlying catalogs. Its primary role is to support extensibility by allowing additional catalogs to be added at runtime, while maintaining a single entry point for module catalog operations.
---
### **Public Interface**
- **`AggregateModuleCatalog()`**
*Constructor.* Initializes a new instance with a default `ModuleCatalog` (stored as the first element in `_catalogs`). This default catalog is used for modules added via `AddModule(ModuleInfo)`.
- **`void AddCatalog(IModuleCatalog catalog)`**
Appends a new `IModuleCatalog` instance to the internal list of catalogs. Throws `ArgumentNullException` if `catalog` is `null`.
- **`IEnumerable<ModuleInfo> Modules { get; }`**
Returns a flattened enumeration of all `ModuleInfo` instances across all contained catalogs, via `SelectMany`.
- **`IEnumerable<ModuleInfo> GetDependentModules(ModuleInfo moduleInfo)`**
Locates the *single* catalog containing `moduleInfo` (via `Single(x => x.Modules.Contains(moduleInfo))`) and delegates the call to that catalog. Returns the modules dependencies as reported by the underlying catalog.
- **`IEnumerable<ModuleInfo> CompleteListWithDependencies(IEnumerable<ModuleInfo> modules)`**
Groups the input `modules` by their source catalog (again using `Single(...)` to identify the catalog), then delegates `CompleteListWithDependencies` per catalog. Returns the union of all dependency-expanded module sets.
- **`void Initialize()`**
Invokes `Initialize()` on each catalog in `_catalogs`, enabling initialization logic (e.g., loading, validation) across all catalogs.
- **`void AddModule(ModuleInfo moduleInfo)`**
Adds `moduleInfo` exclusively to the *first* catalog in `_catalogs` (i.e., the default `ModuleCatalog` created in the constructor). Does *not* attempt to distribute modules across catalogs.
---
### **Invariants**
1. **Catalog Membership Uniqueness**:
`GetDependentModules` and `CompleteListWithDependencies` assume *exactly one* catalog in `_catalogs` contains a given `ModuleInfo`. If a `ModuleInfo` appears in multiple catalogs, `Single(...)` will throw `InvalidOperationException`.
*This implies modules must be unique across all constituent catalogs.*
2. **Default Catalog Preservation**:
The first catalog (`_catalogs[0]`) is *always* the initial `ModuleCatalog` instance created in the constructor. It is *never* removed or replaced.
3. **Module Addition Target**:
All modules added via `AddModule(ModuleInfo)` are placed in `_catalogs[0]`. Modules added via `AddCatalog` may reside in any catalog, but must not duplicate modules already in `_catalogs[0]` (to satisfy uniqueness).
4. **Catalog Initialization Order**:
`Initialize()` calls each catalogs `Initialize()` in the order they appear in `_catalogs`. No ordering guarantees beyond this sequence are specified.
---
### **Dependencies**
- **Depends on**:
- `Microsoft.Practices.Prism.Modularity` (specifically, the `IModuleCatalog` and `ModuleInfo` types).
- `System`, `System.Collections.Generic`, `System.Linq` (for LINQ operations like `SelectMany`, `GroupBy`, `Single`).
- **Depended on by**:
- Inferred from namespace (`DTS.Common`) and class name: likely consumed by Prism-based module initialization logic (e.g., `ModuleManager` or `ModuleInitializer` from Prism), though not explicit in the source.
- No direct usage is visible in this file, but as an `IModuleCatalog` implementation, it is intended for integration with Prisms module loading pipeline.
---
### **Gotchas**
1. **Fragile Catalog Lookup via `Single(...)`**:
`GetDependentModules` and `CompleteListWithDependencies` use `Single(x => x.Modules.Contains(moduleInfo))`, which:
- Fails if a `ModuleInfo` exists in multiple catalogs (throws `InvalidOperationException`).
- Fails if a `ModuleInfo` is *not* found in any catalog (also throws `InvalidOperationException`).
→ This is a critical reliability risk if catalogs overlap or modules are added inconsistently.
2. **Asymmetric `AddModule` Behavior**:
`AddModule` *only* adds to the first catalog (`_catalogs[0]`). Users might expect modules to be distributed or added to a specific catalog, leading to confusion if they add modules expecting them to appear in a custom catalog added via `AddCatalog`.
3. **No Catalog Removal/Reordering Support**:
There is no method to remove catalogs or change their order. The first catalog is fixed, and subsequent catalogs are appended. This limits flexibility in dynamic scenarios.
4. **No Validation of Catalog Compatibility**:
The class does not enforce that catalogs use compatible `ModuleInfo` implementations or metadata schemas. Inconsistent catalogs may cause runtime errors during dependency resolution.
5. **No Thread Safety**:
The class is not marked thread-safe. Concurrent modifications (e.g., `AddCatalog` during enumeration) may cause exceptions.
6. **Assumes `Modules.Contains` Identity Semantics**:
Relies on `IModuleCatalog.Modules.Contains(moduleInfo)` to identify the source catalog. This assumes `ModuleInfo` implements value-based equality (e.g., via `Equals`/`GetHashCode`), which may not hold if `ModuleInfo` uses reference equality.