Program.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  1. using System.Text;
  2. using Apq.Cfg;
  3. using Apq.Cfg.Changes;
  4. using Apq.Cfg.Ini;
  5. using Apq.Cfg.Xml;
  6. using Apq.Cfg.Yaml;
  7. using Apq.Cfg.Toml;
  8. using Microsoft.Extensions.Configuration;
  9. using Microsoft.Extensions.DependencyInjection;
  10. using Microsoft.Extensions.Options;
  11. using Microsoft.Extensions.Primitives;
  12. Console.WriteLine("╔══════════════════════════════════════════════════════════════╗");
  13. Console.WriteLine("║ Apq.Cfg 完整功能示例 ║");
  14. Console.WriteLine("╚══════════════════════════════════════════════════════════════╝\n");
  15. var baseDir = AppContext.BaseDirectory;
  16. // ============================================================================
  17. // 示例 1: 基础用法 - JSON 配置与层级覆盖
  18. // ============================================================================
  19. await Demo1_BasicUsage(baseDir);
  20. // ============================================================================
  21. // 示例 2: 多格式支持 - INI、XML、YAML、TOML
  22. // ============================================================================
  23. await Demo2_MultiFormat(baseDir);
  24. // ============================================================================
  25. // 示例 3: 配置节 (GetSection) 与子键枚举
  26. // ============================================================================
  27. await Demo3_ConfigSection(baseDir);
  28. // ============================================================================
  29. // 示例 4: 批量操作 - GetMany / SetMany
  30. // ============================================================================
  31. await Demo4_BatchOperations(baseDir);
  32. // ============================================================================
  33. // 示例 5: 类型转换
  34. // ============================================================================
  35. await Demo5_TypeConversion(baseDir);
  36. // ============================================================================
  37. // 示例 6: 动态配置重载
  38. // ============================================================================
  39. await Demo6_DynamicReload(baseDir);
  40. // ============================================================================
  41. // 示例 7: 依赖注入集成
  42. // ============================================================================
  43. await Demo7_DependencyInjection(baseDir);
  44. // ============================================================================
  45. // 示例 8: 编码映射配置
  46. // ============================================================================
  47. await Demo8_EncodingMapping(baseDir);
  48. Console.WriteLine("\n╔══════════════════════════════════════════════════════════════╗");
  49. Console.WriteLine("║ 所有示例执行完成 ║");
  50. Console.WriteLine("╚══════════════════════════════════════════════════════════════╝");
  51. // ============================================================================
  52. // 示例实现
  53. // ============================================================================
  54. static async Task Demo1_BasicUsage(string baseDir)
  55. {
  56. Console.WriteLine("═══════════════════════════════════════════════════════════════");
  57. Console.WriteLine("示例 1: 基础用法 - JSON 配置与层级覆盖");
  58. Console.WriteLine("═══════════════════════════════════════════════════════════════\n");
  59. var configPath = Path.Combine(baseDir, "config.json");
  60. var localConfigPath = Path.Combine(baseDir, "config.local.json");
  61. // 创建基础配置
  62. File.WriteAllText(configPath, """
  63. {
  64. "App": {
  65. "Name": "MyApp",
  66. "Version": "1.0.0",
  67. "Debug": false
  68. },
  69. "Database": {
  70. "Host": "localhost",
  71. "Port": 3306,
  72. "Name": "mydb"
  73. }
  74. }
  75. """);
  76. // 创建本地覆盖配置(高优先级)
  77. File.WriteAllText(localConfigPath, """
  78. {
  79. "App": {
  80. "Debug": true
  81. },
  82. "Database": {
  83. "Host": "192.168.1.100"
  84. }
  85. }
  86. """);
  87. // 构建配置:level 越大优先级越高
  88. // 注意:环境变量不可写,所以 isPrimaryWriter 设置在 JSON 配置源上
  89. var cfg = new CfgBuilder()
  90. .AddJson(configPath, level: 0, writeable: false)
  91. .AddJson(localConfigPath, level: 1, writeable: true, isPrimaryWriter: true)
  92. .AddEnvironmentVariables(level: 2, prefix: "MYAPP_")
  93. .Build();
  94. // 读取配置
  95. Console.WriteLine("1.1 读取配置值:");
  96. Console.WriteLine($" App:Name = {cfg.Get("App:Name")}");
  97. Console.WriteLine($" App:Version = {cfg.Get("App:Version")}");
  98. Console.WriteLine($" App:Debug = {cfg.Get("App:Debug")} (被本地配置覆盖为 true)");
  99. Console.WriteLine($" Database:Host = {cfg.Get("Database:Host")} (被本地配置覆盖)");
  100. Console.WriteLine($" Database:Port = {cfg.Get("Database:Port")}");
  101. // 检查配置是否存在
  102. Console.WriteLine("\n1.2 检查配置是否存在:");
  103. Console.WriteLine($" Exists(App:Name) = {cfg.Exists("App:Name")}");
  104. Console.WriteLine($" Exists(NotExist:Key) = {cfg.Exists("NotExist:Key")}");
  105. // 修改配置(写入到 isPrimaryWriter 的配置源,需要指定 targetLevel)
  106. Console.WriteLine("\n1.3 修改配置:");
  107. cfg.Set("App:LastRun", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), targetLevel: 1);
  108. await cfg.SaveAsync(targetLevel: 1);
  109. Console.WriteLine($" 已设置 App:LastRun = {cfg.Get("App:LastRun")}");
  110. // 删除配置
  111. Console.WriteLine("\n1.4 删除配置:");
  112. cfg.Set("App:TempKey", "临时值", targetLevel: 1);
  113. Console.WriteLine($" 设置 App:TempKey = {cfg.Get("App:TempKey")}");
  114. cfg.Remove("App:TempKey", targetLevel: 1);
  115. await cfg.SaveAsync(targetLevel: 1);
  116. Console.WriteLine($" 删除后 App:TempKey = {cfg.Get("App:TempKey") ?? "(null)"}");
  117. // 转换为 Microsoft.Extensions.Configuration
  118. Console.WriteLine("\n1.5 转换为 IConfigurationRoot:");
  119. var msConfig = cfg.ToMicrosoftConfiguration();
  120. Console.WriteLine($" msConfig[\"App:Name\"] = {msConfig["App:Name"]}");
  121. cfg.Dispose();
  122. File.Delete(configPath);
  123. File.Delete(localConfigPath);
  124. Console.WriteLine("\n[示例 1 完成]\n");
  125. }
  126. static async Task Demo2_MultiFormat(string baseDir)
  127. {
  128. Console.WriteLine("═══════════════════════════════════════════════════════════════");
  129. Console.WriteLine("示例 2: 多格式支持 - INI、XML、YAML、TOML");
  130. Console.WriteLine("═══════════════════════════════════════════════════════════════\n");
  131. // INI 格式
  132. var iniPath = Path.Combine(baseDir, "config.ini");
  133. File.WriteAllText(iniPath, """
  134. [App]
  135. Name=IniApp
  136. Version=2.0.0
  137. [Database]
  138. Host=ini-server
  139. Port=5432
  140. """);
  141. // XML 格式
  142. var xmlPath = Path.Combine(baseDir, "config.xml");
  143. File.WriteAllText(xmlPath, """
  144. <?xml version="1.0" encoding="utf-8"?>
  145. <configuration>
  146. <App>
  147. <Name>XmlApp</Name>
  148. <Version>3.0.0</Version>
  149. </App>
  150. <Database>
  151. <Host>xml-server</Host>
  152. <Port>1433</Port>
  153. </Database>
  154. </configuration>
  155. """);
  156. // YAML 格式
  157. var yamlPath = Path.Combine(baseDir, "config.yaml");
  158. File.WriteAllText(yamlPath, """
  159. App:
  160. Name: YamlApp
  161. Version: 4.0.0
  162. Database:
  163. Host: yaml-server
  164. Port: 27017
  165. """);
  166. // TOML 格式
  167. var tomlPath = Path.Combine(baseDir, "config.toml");
  168. File.WriteAllText(tomlPath, """
  169. [App]
  170. Name = "TomlApp"
  171. Version = "5.0.0"
  172. [Database]
  173. Host = "toml-server"
  174. Port = 6379
  175. """);
  176. // 分别测试各格式
  177. Console.WriteLine("2.1 INI 格式:");
  178. using (var iniCfg = new CfgBuilder().AddIni(iniPath, level: 0, writeable: true).Build())
  179. {
  180. Console.WriteLine($" App:Name = {iniCfg.Get("App:Name")}");
  181. Console.WriteLine($" Database:Port = {iniCfg.Get("Database:Port")}");
  182. }
  183. Console.WriteLine("\n2.2 XML 格式:");
  184. using (var xmlCfg = new CfgBuilder().AddXml(xmlPath, level: 0, writeable: true).Build())
  185. {
  186. Console.WriteLine($" App:Name = {xmlCfg.Get("App:Name")}");
  187. Console.WriteLine($" Database:Port = {xmlCfg.Get("Database:Port")}");
  188. }
  189. Console.WriteLine("\n2.3 YAML 格式:");
  190. using (var yamlCfg = new CfgBuilder().AddYaml(yamlPath, level: 0, writeable: true).Build())
  191. {
  192. Console.WriteLine($" App:Name = {yamlCfg.Get("App:Name")}");
  193. Console.WriteLine($" Database:Port = {yamlCfg.Get("Database:Port")}");
  194. }
  195. Console.WriteLine("\n2.4 TOML 格式:");
  196. using (var tomlCfg = new CfgBuilder().AddToml(tomlPath, level: 0, writeable: true).Build())
  197. {
  198. Console.WriteLine($" App:Name = {tomlCfg.Get("App:Name")}");
  199. Console.WriteLine($" Database:Port = {tomlCfg.Get("Database:Port")}");
  200. }
  201. // 混合多种格式
  202. Console.WriteLine("\n2.5 混合多种格式(层级覆盖):");
  203. using var mixedCfg = new CfgBuilder()
  204. .AddIni(iniPath, level: 0, writeable: false)
  205. .AddYaml(yamlPath, level: 1, writeable: false)
  206. .AddToml(tomlPath, level: 2, writeable: true, isPrimaryWriter: true)
  207. .Build();
  208. Console.WriteLine($" App:Name = {mixedCfg.Get("App:Name")} (来自 TOML,最高优先级)");
  209. Console.WriteLine($" App:Version = {mixedCfg.Get("App:Version")} (来自 TOML)");
  210. File.Delete(iniPath);
  211. File.Delete(xmlPath);
  212. File.Delete(yamlPath);
  213. File.Delete(tomlPath);
  214. Console.WriteLine("\n[示例 2 完成]\n");
  215. await Task.CompletedTask;
  216. }
  217. static async Task Demo3_ConfigSection(string baseDir)
  218. {
  219. Console.WriteLine("═══════════════════════════════════════════════════════════════");
  220. Console.WriteLine("示例 3: 配置节 (GetSection) 与子键枚举");
  221. Console.WriteLine("═══════════════════════════════════════════════════════════════\n");
  222. var configPath = Path.Combine(baseDir, "section-demo.json");
  223. File.WriteAllText(configPath, """
  224. {
  225. "Database": {
  226. "Primary": {
  227. "Host": "primary.db.local",
  228. "Port": 3306,
  229. "Username": "admin"
  230. },
  231. "Replica": {
  232. "Host": "replica.db.local",
  233. "Port": 3307,
  234. "Username": "reader"
  235. }
  236. },
  237. "Cache": {
  238. "Redis": {
  239. "Host": "redis.local",
  240. "Port": 6379
  241. }
  242. }
  243. }
  244. """);
  245. using var cfg = new CfgBuilder()
  246. .AddJson(configPath, level: 0, writeable: true, isPrimaryWriter: true)
  247. .Build();
  248. // 获取配置节
  249. Console.WriteLine("3.1 使用 GetSection 简化嵌套访问:");
  250. var dbSection = cfg.GetSection("Database");
  251. var primarySection = dbSection.GetSection("Primary");
  252. Console.WriteLine($" Database:Primary:Host = {primarySection.Get("Host")}");
  253. Console.WriteLine($" Database:Primary:Port = {primarySection.Get<int>("Port")}");
  254. // 枚举子键
  255. Console.WriteLine("\n3.2 枚举配置节的子键:");
  256. Console.WriteLine(" Database 的子键:");
  257. foreach (var key in dbSection.GetChildKeys())
  258. {
  259. Console.WriteLine($" - {key}");
  260. }
  261. Console.WriteLine("\n 顶级配置键:");
  262. foreach (var key in cfg.GetChildKeys())
  263. {
  264. Console.WriteLine($" - {key}");
  265. }
  266. // 通过配置节修改值
  267. Console.WriteLine("\n3.3 通过配置节修改值:");
  268. var replicaSection = dbSection.GetSection("Replica");
  269. replicaSection.Set("Port", "3308");
  270. await cfg.SaveAsync();
  271. Console.WriteLine($" 修改后 Database:Replica:Port = {replicaSection.Get("Port")}");
  272. File.Delete(configPath);
  273. Console.WriteLine("\n[示例 3 完成]\n");
  274. }
  275. static async Task Demo4_BatchOperations(string baseDir)
  276. {
  277. Console.WriteLine("═══════════════════════════════════════════════════════════════");
  278. Console.WriteLine("示例 4: 批量操作 - GetMany / SetMany");
  279. Console.WriteLine("═══════════════════════════════════════════════════════════════\n");
  280. var configPath = Path.Combine(baseDir, "batch-demo.json");
  281. File.WriteAllText(configPath, """
  282. {
  283. "Settings": {
  284. "Theme": "dark",
  285. "Language": "zh-CN",
  286. "FontSize": "14",
  287. "AutoSave": "true"
  288. }
  289. }
  290. """);
  291. using var cfg = new CfgBuilder()
  292. .AddJson(configPath, level: 0, writeable: true, isPrimaryWriter: true)
  293. .Build();
  294. // 批量获取
  295. Console.WriteLine("4.1 批量获取 (GetMany):");
  296. var keys = new[] { "Settings:Theme", "Settings:Language", "Settings:FontSize" };
  297. var values = cfg.GetMany(keys);
  298. foreach (var kv in values)
  299. {
  300. Console.WriteLine($" {kv.Key} = {kv.Value}");
  301. }
  302. // 批量获取并转换类型
  303. Console.WriteLine("\n4.2 批量获取并转换类型 (GetMany<T>):");
  304. var intKeys = new[] { "Settings:FontSize" };
  305. var intValues = cfg.GetMany<int>(intKeys);
  306. foreach (var kv in intValues)
  307. {
  308. Console.WriteLine($" {kv.Key} = {kv.Value} (int)");
  309. }
  310. // 批量设置
  311. Console.WriteLine("\n4.3 批量设置 (SetMany):");
  312. var newValues = new Dictionary<string, string?>
  313. {
  314. ["Settings:Theme"] = "light",
  315. ["Settings:FontSize"] = "16",
  316. ["Settings:NewOption"] = "enabled"
  317. };
  318. cfg.SetMany(newValues);
  319. await cfg.SaveAsync();
  320. Console.WriteLine(" 批量设置后的值:");
  321. var updatedValues = cfg.GetMany(new[] { "Settings:Theme", "Settings:FontSize", "Settings:NewOption" });
  322. foreach (var kv in updatedValues)
  323. {
  324. Console.WriteLine($" {kv.Key} = {kv.Value}");
  325. }
  326. File.Delete(configPath);
  327. Console.WriteLine("\n[示例 4 完成]\n");
  328. }
  329. static async Task Demo5_TypeConversion(string baseDir)
  330. {
  331. Console.WriteLine("═══════════════════════════════════════════════════════════════");
  332. Console.WriteLine("示例 5: 类型转换");
  333. Console.WriteLine("═══════════════════════════════════════════════════════════════\n");
  334. var configPath = Path.Combine(baseDir, "types-demo.json");
  335. File.WriteAllText(configPath, """
  336. {
  337. "Types": {
  338. "IntValue": "42",
  339. "LongValue": "9223372036854775807",
  340. "DoubleValue": "3.14159",
  341. "DecimalValue": "123.456",
  342. "BoolTrue": "true",
  343. "BoolFalse": "false",
  344. "DateValue": "2024-12-25",
  345. "GuidValue": "550e8400-e29b-41d4-a716-446655440000",
  346. "EnumValue": "Warning"
  347. }
  348. }
  349. """);
  350. using var cfg = new CfgBuilder()
  351. .AddJson(configPath, level: 0, writeable: false)
  352. .Build();
  353. Console.WriteLine("5.1 各种类型转换:");
  354. Console.WriteLine($" int: {cfg.Get<int>("Types:IntValue")}");
  355. Console.WriteLine($" long: {cfg.Get<long>("Types:LongValue")}");
  356. Console.WriteLine($" double: {cfg.Get<double>("Types:DoubleValue")}");
  357. Console.WriteLine($" decimal: {cfg.Get<decimal>("Types:DecimalValue")}");
  358. Console.WriteLine($" bool (true): {cfg.Get<bool>("Types:BoolTrue")}");
  359. Console.WriteLine($" bool (false): {cfg.Get<bool>("Types:BoolFalse")}");
  360. Console.WriteLine($" DateTime: {cfg.Get<DateTime>("Types:DateValue"):yyyy-MM-dd}");
  361. Console.WriteLine($" Guid: {cfg.Get<Guid>("Types:GuidValue")}");
  362. Console.WriteLine($" Enum: {cfg.Get<LogLevel>("Types:EnumValue")}");
  363. Console.WriteLine("\n5.2 可空类型与默认值:");
  364. Console.WriteLine($" 不存在的键 (int?): {cfg.Get<int?>("Types:NotExist") ?? -1}");
  365. Console.WriteLine($" 不存在的键 (string): {cfg.Get("Types:NotExist") ?? "(null)"}");
  366. File.Delete(configPath);
  367. Console.WriteLine("\n[示例 5 完成]\n");
  368. await Task.CompletedTask;
  369. }
  370. static async Task Demo6_DynamicReload(string baseDir)
  371. {
  372. Console.WriteLine("═══════════════════════════════════════════════════════════════");
  373. Console.WriteLine("示例 6: 动态配置重载");
  374. Console.WriteLine("═══════════════════════════════════════════════════════════════\n");
  375. var configPath = Path.Combine(baseDir, "reload-demo.json");
  376. File.WriteAllText(configPath, """
  377. {
  378. "App": {
  379. "RefreshInterval": "30"
  380. }
  381. }
  382. """);
  383. // 启用 reloadOnChange
  384. var cfg = new CfgBuilder()
  385. .AddJson(configPath, level: 0, writeable: true, isPrimaryWriter: true, reloadOnChange: true)
  386. .Build();
  387. Console.WriteLine("6.1 配置动态重载选项:");
  388. var msConfig = cfg.ToMicrosoftConfiguration(new DynamicReloadOptions
  389. {
  390. DebounceMs = 100, // 防抖时间
  391. EnableDynamicReload = true, // 启用动态重载
  392. Strategy = ReloadStrategy.Eager, // 立即重载
  393. RollbackOnError = true, // 错误时回滚
  394. HistorySize = 5 // 保留 5 条历史
  395. });
  396. Console.WriteLine(" 已配置: DebounceMs=100, Strategy=Eager, HistorySize=5");
  397. // 使用 IChangeToken 监听变更
  398. Console.WriteLine("\n6.2 使用 IChangeToken 监听变更:");
  399. var changeCount = 0;
  400. ChangeToken.OnChange(
  401. () => msConfig.GetReloadToken(),
  402. () =>
  403. {
  404. changeCount++;
  405. Console.WriteLine($" [IChangeToken] 配置已更新 (第 {changeCount} 次)");
  406. });
  407. Console.WriteLine(" 已注册 IChangeToken 回调");
  408. // 使用 Rx 订阅配置变更
  409. Console.WriteLine("\n6.3 使用 Rx 订阅配置变更:");
  410. using var subscription = cfg.ConfigChanges.Subscribe(e =>
  411. {
  412. Console.WriteLine($" [Rx] 批次 {e.BatchId} - {e.Changes.Count} 个变更:");
  413. foreach (var (key, change) in e.Changes)
  414. {
  415. Console.WriteLine($" [{change.Type}] {key}: {change.OldValue} -> {change.NewValue}");
  416. }
  417. });
  418. Console.WriteLine(" 已订阅 ConfigChanges");
  419. // 模拟配置变更
  420. Console.WriteLine("\n6.4 模拟配置变更:");
  421. Console.WriteLine(" 修改 App:RefreshInterval 为 60...");
  422. cfg.Set("App:RefreshInterval", "60");
  423. await cfg.SaveAsync();
  424. // 等待变更通知
  425. await Task.Delay(200);
  426. Console.WriteLine($"\n 当前值: App:RefreshInterval = {cfg.Get("App:RefreshInterval")}");
  427. cfg.Dispose();
  428. File.Delete(configPath);
  429. Console.WriteLine("\n[示例 6 完成]\n");
  430. }
  431. static async Task Demo7_DependencyInjection(string baseDir)
  432. {
  433. Console.WriteLine("═══════════════════════════════════════════════════════════════");
  434. Console.WriteLine("示例 7: 依赖注入集成");
  435. Console.WriteLine("═══════════════════════════════════════════════════════════════\n");
  436. var configPath = Path.Combine(baseDir, "di-demo.json");
  437. File.WriteAllText(configPath, """
  438. {
  439. "Database": {
  440. "Host": "db.example.com",
  441. "Port": "5432",
  442. "Name": "production"
  443. },
  444. "Logging": {
  445. "Level": "Information",
  446. "EnableConsole": "true"
  447. }
  448. }
  449. """);
  450. // 配置服务容器
  451. var services = new ServiceCollection();
  452. // 方式1: 使用 AddApqCfg 注册配置
  453. Console.WriteLine("7.1 注册 Apq.Cfg 到 DI 容器:");
  454. services.AddApqCfg(cfg => cfg
  455. .AddJson(configPath, level: 0, writeable: true, isPrimaryWriter: true));
  456. Console.WriteLine(" 已注册 ICfgRoot 和 IConfigurationRoot");
  457. // 方式2: 绑定强类型配置
  458. Console.WriteLine("\n7.2 绑定强类型配置:");
  459. services.ConfigureApqCfg<DatabaseOptions>("Database");
  460. services.ConfigureApqCfg<LoggingOptions>("Logging");
  461. Console.WriteLine(" 已绑定 DatabaseOptions 和 LoggingOptions");
  462. // 构建服务提供者
  463. var provider = services.BuildServiceProvider();
  464. // 获取服务
  465. Console.WriteLine("\n7.3 从 DI 容器获取服务:");
  466. var cfgRoot = provider.GetRequiredService<ICfgRoot>();
  467. var msConfig = provider.GetRequiredService<IConfigurationRoot>();
  468. var dbOptions = provider.GetRequiredService<IOptions<DatabaseOptions>>().Value;
  469. var logOptions = provider.GetRequiredService<IOptions<LoggingOptions>>().Value;
  470. Console.WriteLine($" ICfgRoot: Database:Host = {cfgRoot.Get("Database:Host")}");
  471. Console.WriteLine($" IConfigurationRoot: Database:Host = {msConfig["Database:Host"]}");
  472. Console.WriteLine($" DatabaseOptions: Host={dbOptions.Host}, Port={dbOptions.Port}, Name={dbOptions.Name}");
  473. Console.WriteLine($" LoggingOptions: Level={logOptions.Level}, EnableConsole={logOptions.EnableConsole}");
  474. // 清理
  475. if (provider is IDisposable disposable)
  476. disposable.Dispose();
  477. File.Delete(configPath);
  478. Console.WriteLine("\n[示例 7 完成]\n");
  479. await Task.CompletedTask;
  480. }
  481. static async Task Demo8_EncodingMapping(string baseDir)
  482. {
  483. Console.WriteLine("═══════════════════════════════════════════════════════════════");
  484. Console.WriteLine("示例 8: 编码映射配置");
  485. Console.WriteLine("═══════════════════════════════════════════════════════════════\n");
  486. var configPath = Path.Combine(baseDir, "encoding-demo.json");
  487. File.WriteAllText(configPath, """
  488. {
  489. "App": {
  490. "Name": "编码测试应用",
  491. "Description": "支持中文和特殊字符: äöü ñ 日本語"
  492. }
  493. }
  494. """, Encoding.UTF8);
  495. Console.WriteLine("8.1 编码检测置信度阈值:");
  496. var cfg1 = new CfgBuilder()
  497. .WithEncodingConfidenceThreshold(0.7f)
  498. .AddJson(configPath, level: 0, writeable: false)
  499. .Build();
  500. Console.WriteLine($" 置信度阈值设置为 0.7");
  501. Console.WriteLine($" App:Name = {cfg1.Get("App:Name")}");
  502. cfg1.Dispose();
  503. Console.WriteLine("\n8.2 编码检测日志:");
  504. var cfg2 = new CfgBuilder()
  505. .WithEncodingDetectionLogging(result =>
  506. {
  507. Console.WriteLine($" [编码检测] 文件: {Path.GetFileName(result.FilePath)}");
  508. Console.WriteLine($" 编码: {result.Encoding.EncodingName}");
  509. Console.WriteLine($" 置信度: {result.Confidence:P0}");
  510. Console.WriteLine($" 方法: {result.Method}");
  511. })
  512. .AddJson(configPath, level: 0, writeable: false)
  513. .Build();
  514. cfg2.Dispose();
  515. Console.WriteLine("\n8.3 编码映射规则:");
  516. Console.WriteLine(" 支持三种映射方式:");
  517. Console.WriteLine(" - 完整路径: AddReadEncodingMapping(path, encoding)");
  518. Console.WriteLine(" - 通配符: AddReadEncodingMappingWildcard(\"*.json\", encoding)");
  519. Console.WriteLine(" - 正则: AddReadEncodingMappingRegex(@\"config.*\\.json$\", encoding)");
  520. // 演示编码映射配置
  521. var cfg3 = new CfgBuilder()
  522. // 为特定文件指定编码
  523. .AddReadEncodingMapping(configPath, Encoding.UTF8, priority: 100)
  524. // 为所有 JSON 文件指定写入编码
  525. .AddWriteEncodingMappingWildcard("*.json", new UTF8Encoding(false), priority: 50)
  526. .AddJson(configPath, level: 0, writeable: false)
  527. .Build();
  528. Console.WriteLine("\n 已配置编码映射规则");
  529. Console.WriteLine($" App:Description = {cfg3.Get("App:Description")}");
  530. cfg3.Dispose();
  531. File.Delete(configPath);
  532. Console.WriteLine("\n[示例 8 完成]\n");
  533. await Task.CompletedTask;
  534. }
  535. // ============================================================================
  536. // 强类型配置类
  537. // ============================================================================
  538. public class DatabaseOptions
  539. {
  540. public string? Host { get; set; }
  541. public int Port { get; set; }
  542. public string? Name { get; set; }
  543. }
  544. public class LoggingOptions
  545. {
  546. public string? Level { get; set; }
  547. public bool EnableConsole { get; set; }
  548. }
  549. // 用于类型转换示例的枚举
  550. public enum LogLevel { Debug, Info, Warning, Error }