181 lines
8.0 KiB
Markdown
181 lines
8.0 KiB
Markdown
|
|
---
|
|||
|
|
source_files:
|
|||
|
|
- Common/DTS.Common.Core/Settings/SettingsChangedEventArgs.cs
|
|||
|
|
- Common/DTS.Common.Core/Settings/SettingsCollection.cs
|
|||
|
|
generated_at: "2026-04-16T02:05:44.714308+00:00"
|
|||
|
|
model: "Qwen/Qwen3-Coder-Next-FP8"
|
|||
|
|
schema_version: 1
|
|||
|
|
sha256: "e48bcdd1082dba01"
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# Settings Collection Module Documentation
|
|||
|
|
|
|||
|
|
## 1. Purpose
|
|||
|
|
|
|||
|
|
This module provides a dictionary-based settings collection (`SettingsCollection<TKey, TItem>`) that extends standard dictionary functionality by raising events whenever items are added, removed, modified, or the entire collection is cleared. It exists to enable reactive UIs or other subsystems to respond to configuration changes in real time, without requiring manual polling or external event coordination. The module is part of the core settings infrastructure in the DTS system and is designed for use in scenarios where settings changes must be tracked and propagated.
|
|||
|
|
|
|||
|
|
## 2. Public Interface
|
|||
|
|
|
|||
|
|
### `SettingsCollection<TKey, TItem>` Class
|
|||
|
|
|
|||
|
|
A generic collection implementing `IDictionary<TKey, TItem>` that fires events on modifications.
|
|||
|
|
|
|||
|
|
#### Public Events
|
|||
|
|
|
|||
|
|
- **`event EventHandler<SettingsChangedEventArgs<TKey, TItem>> CollectionItemPropertyChanged`**
|
|||
|
|
Fired whenever an item is added, removed, modified, or the collection is cleared. Subscribers receive detailed information about the change via `SettingsChangedEventArgs`.
|
|||
|
|
|
|||
|
|
#### Public Methods (from `IDictionary<TKey, TItem>`)
|
|||
|
|
|
|||
|
|
- **`void Add(TKey key, TItem value)`**
|
|||
|
|
Adds a new key-value pair to the collection. Fires `CollectionItemPropertyChanged` with `ChangeSettingType.Add`, including `key` and `value`.
|
|||
|
|
|
|||
|
|
- **`bool ContainsKey(TKey key)`**
|
|||
|
|
Returns `true` if the specified key exists in the collection.
|
|||
|
|
|
|||
|
|
- **`bool Remove(TKey key)`**
|
|||
|
|
Removes the entry with the specified key. Returns `true` if removal succeeded. Fires `CollectionItemPropertyChanged` with `ChangeSettingType.Remove` and the `key`.
|
|||
|
|
|
|||
|
|
- **`bool TryGetValue(TKey key, out TItem value)`**
|
|||
|
|
Attempts to retrieve the value for a given key. Returns `true` if found.
|
|||
|
|
|
|||
|
|
- **`void Clear()`**
|
|||
|
|
Removes all entries from the collection. Fires `CollectionItemPropertyChanged` with `ChangeSettingType.ClearAll`.
|
|||
|
|
|
|||
|
|
- **`bool Remove(KeyValuePair<TKey, TItem> item)`**
|
|||
|
|
Removes the specified key-value pair (by key only). Fires `CollectionItemPropertyChanged` with `ChangeSettingType.Remove` and the key.
|
|||
|
|
|
|||
|
|
- **`void Add(KeyValuePair<TKey, TItem> item)`**
|
|||
|
|
Adds the specified key-value pair. Fires `CollectionItemPropertyChanged` with `ChangeSettingType.Add`, including key and value.
|
|||
|
|
|
|||
|
|
#### Public Properties (from `IDictionary<TKey, TItem>`)
|
|||
|
|
|
|||
|
|
- **`TItem this[TKey key] { get; set; }`**
|
|||
|
|
Indexer for getting/setting values.
|
|||
|
|
- **Getter**: Returns the value for the given key (throws `KeyNotFoundException` if not present).
|
|||
|
|
- **Setter**: Sets or overwrites the value for the key. **Note**: Always fires `ChangeSettingType.Add`, even when overwriting an existing key (see *Gotchas*).
|
|||
|
|
|
|||
|
|
- **`ICollection<TKey> Keys`**
|
|||
|
|
Returns a read-only collection of all keys.
|
|||
|
|
|
|||
|
|
- **`ICollection<TItem> Values`**
|
|||
|
|
Returns a read-only collection of all values.
|
|||
|
|
|
|||
|
|
- **`int Count`**
|
|||
|
|
Returns the number of entries in the collection.
|
|||
|
|
|
|||
|
|
- **`bool IsReadOnly`**
|
|||
|
|
Always `false`; this collection is mutable.
|
|||
|
|
|
|||
|
|
#### Public Properties (non-interface)
|
|||
|
|
|
|||
|
|
- **`ICollection<TKey> Keys`**
|
|||
|
|
(Same as above.)
|
|||
|
|
|
|||
|
|
- **`ICollection<TItem> Values`**
|
|||
|
|
(Same as above.)
|
|||
|
|
|
|||
|
|
> **Note**: `CopyTo` throws `NotImplementedException`.
|
|||
|
|
|
|||
|
|
### `SettingsChangedEventArgs<TKey, TItem>` Class
|
|||
|
|
|
|||
|
|
Event arguments providing context for a change.
|
|||
|
|
|
|||
|
|
#### Constructors
|
|||
|
|
|
|||
|
|
- **`SettingsChangedEventArgs(ChangeSettingType changeType)`**
|
|||
|
|
For changes that do not involve a specific key or item (e.g., `ClearAll`).
|
|||
|
|
|
|||
|
|
- **`SettingsChangedEventArgs(ChangeSettingType changeType, TKey key)`**
|
|||
|
|
For changes involving a key but no value (e.g., `Remove`).
|
|||
|
|
|
|||
|
|
- **`SettingsChangedEventArgs(ChangeSettingType changeType, TKey key, TItem item)`**
|
|||
|
|
For changes involving both key and value (e.g., `Add`, `Modified`, or indexer set).
|
|||
|
|
|
|||
|
|
#### Public Properties
|
|||
|
|
|
|||
|
|
- **`ChangeType`** (`ChangeSettingType`)
|
|||
|
|
The type of change that occurred.
|
|||
|
|
|
|||
|
|
- **`Key`** (`TKey`)
|
|||
|
|
The key associated with the change. May be default (`null`/`0`/etc.) for `ClearAll`.
|
|||
|
|
|
|||
|
|
- **`Item`** (`TItem`)
|
|||
|
|
The value associated with the change. May be default for `Remove` or `ClearAll`.
|
|||
|
|
|
|||
|
|
### `ChangeSettingType` Enum
|
|||
|
|
|
|||
|
|
- **`Add = 0`**
|
|||
|
|
A new item was added.
|
|||
|
|
|
|||
|
|
- **`Remove = 1`**
|
|||
|
|
An item was removed.
|
|||
|
|
|
|||
|
|
- **`Modified = 3`**
|
|||
|
|
An item was modified.
|
|||
|
|
> **Note**: This value exists but is *never used* in the current implementation.
|
|||
|
|
|
|||
|
|
- **`ClearAll = 4`**
|
|||
|
|
The entire collection was cleared.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. Invariants
|
|||
|
|
|
|||
|
|
- **Event Firing Guarantee**:
|
|||
|
|
Every mutation operation (`Add`, `Remove`, `Clear`, indexer set) *always* fires `CollectionItemPropertyChanged` exactly once per operation.
|
|||
|
|
|
|||
|
|
- **Event Payload Consistency**:
|
|||
|
|
- `Add`, `Modified`, and indexer set → `ChangeType = Add`, with `Key` and `Item` populated.
|
|||
|
|
- `Remove` → `ChangeType = Remove`, with `Key` populated, `Item = default`.
|
|||
|
|
- `Clear` → `ChangeType = ClearAll`, with `Key = default`, `Item = default`.
|
|||
|
|
|
|||
|
|
- **No `Modified` Events**:
|
|||
|
|
Although `ChangeSettingType.Modified` is defined, it is *never* used. The indexer setter always fires `Add`, even when overwriting an existing key.
|
|||
|
|
|
|||
|
|
- **Read-only properties are enforced**:
|
|||
|
|
`IsReadOnly` is always `false`; the collection is fully mutable.
|
|||
|
|
|
|||
|
|
- **No deep copy on `CopyTo`**:
|
|||
|
|
`CopyTo` is unimplemented and throws `NotImplementedException`.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4. Dependencies
|
|||
|
|
|
|||
|
|
### Dependencies *of* this module:
|
|||
|
|
- **`System`** (core .NET types: `EventArgs`, `EventHandler`, `Dictionary<TKey, TValue>`, `ICollection<TKey>`, `IEnumerator`, etc.)
|
|||
|
|
|
|||
|
|
### Dependencies *on* this module:
|
|||
|
|
- **`DTS.Common.Core.Settings` namespace** (self-contained; no external references beyond `System`).
|
|||
|
|
- **Consumers**: Based on naming and design, this module is intended to be used by higher-level settings management components (e.g., `ISettingsService`, UI binding layers) that need to react to configuration changes. No explicit usages are visible in the provided source.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 5. Gotchas
|
|||
|
|
|
|||
|
|
- **`Modified` is unused**:
|
|||
|
|
The `ChangeSettingType.Modified` enum value is defined but never emitted. If a change is made via the indexer (`collection[key] = value`), it fires `ChangeSettingType.Add`, not `Modified`. This may mislead consumers expecting `Modified` for updates.
|
|||
|
|
|
|||
|
|
- **Indexer setter mislabels overwrites as `Add`**:
|
|||
|
|
Setting an existing key via `collection[key] = newValue` fires `ChangeSettingType.Add`, not `Modified`. This could cause incorrect behavior in listeners that distinguish between *new* additions and *updates*.
|
|||
|
|
|
|||
|
|
- **`CopyTo` is unimplemented**:
|
|||
|
|
Calling `CopyTo` throws `NotImplementedException`. This violates the `ICollection<KeyValuePair<TKey, TItem>>` contract and may break serialization or bulk-copy scenarios.
|
|||
|
|
|
|||
|
|
- **No validation on `Key` or `Item`**:
|
|||
|
|
The collection does not enforce non-null keys (unless `TKey` is a value type) or validate item values. Behavior with `null` keys depends on `Dictionary<TKey, TItem>`’s implementation (throws if `TKey` is a reference type and `null` is passed, unless a custom comparer is used—but none is provided).
|
|||
|
|
|
|||
|
|
- **No thread-safety guarantees**:
|
|||
|
|
The module uses a private `Dictionary<TKey, TItem>` without synchronization. Concurrent access (e.g., from multiple threads) may cause race conditions or exceptions.
|
|||
|
|
|
|||
|
|
- **`Contains(KeyValuePair<TKey, TItem>)` is inefficient**:
|
|||
|
|
It checks both `ContainsKey` *and* `ContainsValue`, which is O(n) for the value check. This may be unexpected for a dictionary-like structure.
|
|||
|
|
|
|||
|
|
- **No `Modified` event overload**:
|
|||
|
|
The private `FireItemChangedEvent` overloads do not distinguish between `Add` and `Modified`—they only dispatch based on `ChangeSettingType`. Since `Modified` is unused, this is consistent but limits extensibility.
|
|||
|
|
|
|||
|
|
- **Event subscribers may receive stale data**:
|
|||
|
|
If a subscriber modifies the collection during event handling (e.g., in response to `Add`), it may trigger nested events or reentrancy issues. No recursion guard is present.
|
|||
|
|
|
|||
|
|
None identified beyond the above.
|