using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Primitives; namespace BuildFlow.Platform.Tests; /// 极简字典实现的 IConfiguration,仅供测试使用。 /// 完整实现 GetSection/GetChildren,让 GetValue<T> 扩展方法(走 ConfigurationBinder)能正确工作。 /// 注意:ConfigurationBinder.GetValue 内部调用 GetSection(key).Value,故必须返回有效 section。 internal sealed class DictionaryConfiguration : IConfiguration { private readonly Dictionary _values = []; public string? this[string key] { get => _values.TryGetValue(key, out var v) ? v : null; set => _values[key] = value; } // 支持集合初始化器语法:new DictionaryConfiguration { ["k"] = "v" } public void Add(string key, string? value) => _values[key] = value; IEnumerable IConfiguration.GetChildren() => _values.Select(kv => (IConfigurationSection)new LeafSection(kv.Key, kv.Value)).ToList(); IChangeToken IConfiguration.GetReloadToken() => EmptyChangeToken.Instance; IConfigurationSection IConfiguration.GetSection(string key) => new LeafSection(key, _values.TryGetValue(key, out var v) ? v : null); private sealed class LeafSection(string key, string? value) : IConfigurationSection { public string Key => key; public string Path => key; public string? Value { get; set; } = value; string? IConfiguration.this[string childKey] { get => null; set { } } IConfigurationSection IConfiguration.GetSection(string childKey) => new LeafSection($"{key}:{childKey}", null); IEnumerable IConfiguration.GetChildren() => []; IChangeToken IConfiguration.GetReloadToken() => EmptyChangeToken.Instance; } /// 永不变更的占位 IChangeToken,避免引入额外包依赖。 private sealed class EmptyChangeToken : IChangeToken { public static readonly EmptyChangeToken Instance = new(); public bool ActiveChangeCallbacks => false; public bool HasChanged => false; public IDisposable RegisterChangeCallback(Action callback, object? state) => new NoopDisposable(); private sealed class NoopDisposable : IDisposable { public void Dispose() { } } } }