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;
}
}