GFramework/GFramework.Game/Config/InMemoryConfigTable.cs
gewuyou ff553977e3 chore(license): 补齐 Apache-2.0 文件头治理
- 新增许可证文件头检查与修复脚本

- 补充维护者手动修复 PR 工作流和 CI 校验

- 更新贡献指南中的文件头说明

- 补齐仓库维护源码和配置文件的许可证声明
2026-05-03 19:39:49 +08:00

121 lines
4.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright (c) 2025-2026 GeWuYou
// SPDX-License-Identifier: Apache-2.0
using System.Collections.ObjectModel;
using GFramework.Game.Abstractions.Config;
namespace GFramework.Game.Config;
/// <summary>
/// 基于内存字典的只读配置表实现。
/// 该实现用于 Runtime MVP 阶段,为加载器和注册表提供稳定的只读查询对象。
/// </summary>
/// <typeparam name="TKey">配置表主键类型。</typeparam>
/// <typeparam name="TValue">配置项值类型。</typeparam>
public sealed class InMemoryConfigTable<TKey, TValue> : IConfigTable<TKey, TValue>
where TKey : notnull
{
private readonly IReadOnlyCollection<TValue> _allValues;
private readonly IReadOnlyDictionary<TKey, TValue> _entries;
/// <summary>
/// 使用配置项序列和主键选择器创建内存配置表。
/// </summary>
/// <param name="values">配置项序列。</param>
/// <param name="keySelector">用于提取主键的委托。</param>
/// <param name="comparer">可选的主键比较器。</param>
/// <exception cref="ArgumentNullException">当 <paramref name="values" /> 或 <paramref name="keySelector" /> 为空时抛出。</exception>
/// <exception cref="InvalidOperationException">当配置项主键重复时抛出。</exception>
public InMemoryConfigTable(
IEnumerable<TValue> values,
Func<TValue, TKey> keySelector,
IEqualityComparer<TKey>? comparer = null)
{
ArgumentNullException.ThrowIfNull(values);
ArgumentNullException.ThrowIfNull(keySelector);
var dictionary = new Dictionary<TKey, TValue>(comparer);
var allValues = new List<TValue>();
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<TKey, TValue>(dictionary);
_allValues = new ReadOnlyCollection<TValue>(allValues);
}
/// <summary>
/// 获取配置表的主键类型。
/// </summary>
public Type KeyType => typeof(TKey);
/// <summary>
/// 获取配置表的值类型。
/// </summary>
public Type ValueType => typeof(TValue);
/// <summary>
/// 获取配置表中配置项的数量。
/// </summary>
public int Count => _entries.Count;
/// <summary>
/// 根据主键获取配置项的值。
/// </summary>
/// <param name="key">要查找的配置项主键。</param>
/// <returns>返回对应主键的配置项值。</returns>
/// <exception cref="KeyNotFoundException">当指定主键的配置项不存在时抛出。</exception>
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;
}
/// <summary>
/// 尝试根据主键获取配置项的值,操作失败时不会抛出异常。
/// </summary>
/// <param name="key">要查找的配置项主键。</param>
/// <param name="value">
/// 输出参数,如果查找成功则返回对应的配置项值,否则为默认值。
/// </param>
/// <returns>如果找到指定主键的配置项则返回 true否则返回 false。</returns>
public bool TryGet(TKey key, out TValue? value)
{
return _entries.TryGetValue(key, out value);
}
/// <summary>
/// 检查指定主键的配置项是否存在于配置表中。
/// </summary>
/// <param name="key">要检查的配置项主键。</param>
/// <returns>如果配置项已存在则返回 true否则返回 false。</returns>
public bool ContainsKey(TKey key)
{
return _entries.ContainsKey(key);
}
/// <summary>
/// 获取配置表中所有配置项的集合。
/// </summary>
/// <returns>返回所有配置项值的只读集合。</returns>
public IReadOnlyCollection<TValue> All()
{
return _allValues;
}
}