ConnectionStrings:DefaultConnection=DataSource=app.db;Cache=Shared
Logging:LogLevel:Default=Information
Logging:LogLevel:Microsoft=Warning
Logging:LogLevel:Microsoft.Hosting.Lifetime=Information
AllowedHosts=*
using System;
using System.Collections.Generic;
using System.IO;
public class HierarchicalConfig
{
// 使用不区分大小写的字典存储键值对
private readonly Dictionary<string, string> _values =
new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
/// <summary>
/// 从文件加载配置
/// </summary>
/// <param name="filePath">配置文件路径</param>
/// <param name="encoding">文件编码,默认 UTF-8</param>
public HierarchicalConfig(string filePath, Encoding encoding = null)
{
if (encoding == null) encoding = Encoding.UTF8;
Load(filePath, encoding);
}
private void Load(string filePath, Encoding encoding)
{
if (!File.Exists(filePath))
throw new FileNotFoundException("配置文件不存在", filePath);
foreach (string line in File.ReadAllLines(filePath, encoding))
{
string trimmed = line.Trim();
// 忽略空行和注释(支持 # 和 ; 开头的注释)
if (string.IsNullOrEmpty(trimmed) || trimmed.StartsWith("#") || trimmed.StartsWith(";"))
continue;
int equalIndex = trimmed.IndexOf('=');
if (equalIndex <= 0) // 没有等号或等号在开头(无效)
continue;
string key = trimmed.Substring(0, equalIndex).TrimEnd(); // 键,保留原始大小写
string value = trimmed.Substring(equalIndex + 1).TrimStart();
// 可选:去除值两端的引号(如果值用引号包围)
if (value.Length >= 2)
{
if ((value[0] == '"' && value[^1] == '"') || (value[0] == '\'' && value[^1] == '\''))
value = value.Substring(1, value.Length - 2);
}
// 存储完整键路径(保留冒号分隔符)
_values[key] = value;
}
}
/// <summary>
/// 获取指定键的值
/// </summary>
/// <param name="keyPath">键路径,如 "Logging:LogLevel:Default"</param>
/// <param name="defaultValue">键不存在时返回的默认值</param>
public string GetValue(string keyPath, string defaultValue = null)
{
return _values.TryGetValue(keyPath, out string value) ? value : defaultValue;
}
/// <summary>
/// 判断指定键是否存在
/// </summary>
/// <param name="keyPath">键路径,如 "ConnectionStrings:DefaultConnection"</param>
public bool ContainsKey(string keyPath)
{
return _values.ContainsKey(keyPath);
}
/// <summary>
/// 获取所有以某前缀开头的键值对(可用于模拟“节”)
/// </summary>
/// <param name="prefix">前缀,如 "Logging:"</param>
public IEnumerable<KeyValuePair<string, string>> GetValuesWithPrefix(string prefix)
{
foreach (var kv in _values)
{
if (kv.Key.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
yield return kv;
}
}
}