using System.Collections.ObjectModel; using GFramework.Game.Abstractions.Config; namespace GFramework.Game.Config; /// /// 基于内存字典的只读配置表实现。 /// 该实现用于 Runtime MVP 阶段,为加载器和注册表提供稳定的只读查询对象。 /// /// 配置表主键类型。 /// 配置项值类型。 public sealed class InMemoryConfigTable : IConfigTable where TKey : notnull { private readonly IReadOnlyCollection _allValues; private readonly IReadOnlyDictionary _entries; /// /// 使用配置项序列和主键选择器创建内存配置表。 /// /// 配置项序列。 /// 用于提取主键的委托。 /// 可选的主键比较器。 /// 为空时抛出。 /// 当配置项主键重复时抛出。 public InMemoryConfigTable( IEnumerable values, Func keySelector, IEqualityComparer? comparer = null) { ArgumentNullException.ThrowIfNull(values); ArgumentNullException.ThrowIfNull(keySelector); var dictionary = new Dictionary(comparer); var allValues = new List(); foreach (var value in values) { var key = keySelector(value); // 配置表必须在加载期拒绝重复主键,否则运行期查询结果将不可预测。 if (!dictionary.TryAdd(key, value)) { throw new InvalidOperationException( $"Duplicate config key '{key}' was detected for table value type '{typeof(TValue).Name}'."); } allValues.Add(value); } _entries = new ReadOnlyDictionary(dictionary); _allValues = new ReadOnlyCollection(allValues); } /// /// 获取配置表的主键类型。 /// public Type KeyType => typeof(TKey); /// /// 获取配置表的值类型。 /// public Type ValueType => typeof(TValue); /// /// 获取配置表中配置项的数量。 /// public int Count => _entries.Count; /// /// 根据主键获取配置项的值。 /// /// 要查找的配置项主键。 /// 返回对应主键的配置项值。 /// 当指定主键的配置项不存在时抛出。 public TValue Get(TKey key) { if (!_entries.TryGetValue(key, out var value)) { throw new KeyNotFoundException( $"Config key '{key}' was not found in table '{typeof(TValue).Name}'."); } return value; } /// /// 尝试根据主键获取配置项的值,操作失败时不会抛出异常。 /// /// 要查找的配置项主键。 /// /// 输出参数,如果查找成功则返回对应的配置项值,否则为默认值。 /// /// 如果找到指定主键的配置项则返回 true,否则返回 false。 public bool TryGet(TKey key, out TValue? value) { return _entries.TryGetValue(key, out value); } /// /// 检查指定主键的配置项是否存在于配置表中。 /// /// 要检查的配置项主键。 /// 如果配置项已存在则返回 true,否则返回 false。 public bool ContainsKey(TKey key) { return _entries.ContainsKey(key); } /// /// 获取配置表中所有配置项的集合。 /// /// 返回所有配置项值的只读集合。 public IReadOnlyCollection All() { return _allValues; } }