using Apq.Cfg;
namespace Apq.Cfg.Samples.Demos;
///
/// 示例 17: 源生成器(零反射绑定)
/// 演示如何使用 Apq.Cfg.SourceGenerator 实现零反射配置绑定
///
public static class SourceGeneratorDemo
{
public static async Task RunAsync(string baseDir)
{
Console.WriteLine("═══════════════════════════════════════════════════════════════");
Console.WriteLine("示例 17: 源生成器(零反射绑定)");
Console.WriteLine("═══════════════════════════════════════════════════════════════\n");
Console.WriteLine("【源生成器说明】");
Console.WriteLine("Apq.Cfg.SourceGenerator 使用 Roslyn 源生成器在编译时生成配置绑定代码。");
Console.WriteLine("优势:零反射、Native AOT 兼容、编译时类型检查。\n");
// 示例 1: 基本用法
Console.WriteLine("--- 示例 17.1: 基本用法 ---");
ShowBasicUsage();
// 示例 2: 定义配置类
Console.WriteLine("\n--- 示例 17.2: 定义配置类 ---");
ShowConfigClassDefinition();
// 示例 3: 使用生成的绑定方法
Console.WriteLine("\n--- 示例 17.3: 使用生成的绑定方法 ---");
ShowBindingMethods();
// 示例 4: 支持的类型
Console.WriteLine("\n--- 示例 17.4: 支持的类型 ---");
ShowSupportedTypes();
// 示例 5: 嵌套配置
Console.WriteLine("\n--- 示例 17.5: 嵌套配置 ---");
ShowNestedConfiguration();
// 示例 6: 集合类型
Console.WriteLine("\n--- 示例 17.6: 集合类型 ---");
ShowCollectionTypes();
// 示例 7: 查看生成的代码
Console.WriteLine("\n--- 示例 17.7: 查看生成的代码 ---");
ShowGeneratedCode();
// 示例 8: 实际演示
Console.WriteLine("\n--- 示例 17.8: 实际演示 ---");
await DemoActualUsageAsync(baseDir);
Console.WriteLine("\n示例 17 完成\n");
}
private static void ShowBasicUsage()
{
Console.WriteLine("基本用法:");
Console.WriteLine(@"
// 1. 安装 NuGet 包
// dotnet add package Apq.Cfg.SourceGenerator
// 2. 定义配置类(必须是 partial 类)
[CfgSection(""AppSettings"")]
public partial class AppConfig
{
public string? Name { get; set; }
public int Port { get; set; }
}
// 3. 使用生成的绑定方法
var cfg = new CfgBuilder()
.AddJson(""config.json"")
.Build();
var appConfig = AppConfig.BindFrom(cfg.GetSection(""AppSettings""));
Console.WriteLine($""Name: {appConfig.Name}, Port: {appConfig.Port}"");
");
}
private static void ShowConfigClassDefinition()
{
Console.WriteLine("配置类定义规则:");
Console.WriteLine(@"
// 1. 使用 [CfgSection] 特性标记
// 2. 类必须是 partial 的
// 3. 属性必须有 public getter 和 setter
using Apq.Cfg;
// 指定配置节路径
[CfgSection(""Database"")]
public partial class DatabaseConfig
{
public string? Host { get; set; }
public int Port { get; set; } = 5432; // 支持默认值
public string? Name { get; set; }
}
// 不指定路径时,使用类名(去掉 Config/Settings 后缀)
[CfgSection]
public partial class LoggingConfig
{
public string? Level { get; set; }
public bool EnableConsole { get; set; }
}
// 禁用扩展方法生成
[CfgSection(""Cache"", GenerateExtension = false)]
public partial class CacheConfig
{
public string? Provider { get; set; }
public int ExpirationMinutes { get; set; }
}
");
}
private static void ShowBindingMethods()
{
Console.WriteLine("生成的绑定方法:");
Console.WriteLine(@"
// 源生成器会为每个配置类生成以下方法:
// 1. BindFrom - 从配置节创建新实例
var config = DatabaseConfig.BindFrom(cfgRoot.GetSection(""Database""));
// 2. BindTo - 绑定到已有实例
var existingConfig = new DatabaseConfig();
DatabaseConfig.BindTo(cfgRoot.GetSection(""Database""), existingConfig);
// 3. 扩展方法(如果指定了 SectionPath)
var config2 = cfgRoot.GetDatabaseConfig(); // 自动生成的扩展方法
");
}
private static void ShowSupportedTypes()
{
Console.WriteLine("支持的类型:");
Console.WriteLine(@"
[CfgSection(""TypeDemo"")]
public partial class TypeDemoConfig
{
// 字符串
public string? StringValue { get; set; }
// 数值类型
public int IntValue { get; set; }
public long LongValue { get; set; }
public double DoubleValue { get; set; }
public decimal DecimalValue { get; set; }
// 布尔
public bool BoolValue { get; set; }
// 日期时间
public DateTime DateTimeValue { get; set; }
public DateTimeOffset DateTimeOffsetValue { get; set; }
public TimeSpan TimeSpanValue { get; set; }
public DateOnly DateOnlyValue { get; set; } // .NET 6+
public TimeOnly TimeOnlyValue { get; set; } // .NET 6+
// 其他
public Guid GuidValue { get; set; }
public Uri? UriValue { get; set; }
// 枚举
public LogLevel LogLevel { get; set; }
// 可空类型
public int? NullableInt { get; set; }
public DateTime? NullableDateTime { get; set; }
}
public enum LogLevel { Debug, Info, Warning, Error }
");
}
private static void ShowNestedConfiguration()
{
Console.WriteLine("嵌套配置:");
Console.WriteLine(@"
// 嵌套的配置类也需要标记 [CfgSection]
[CfgSection(""App"")]
public partial class AppConfig
{
public string? Name { get; set; }
public DatabaseConfig? Database { get; set; } // 嵌套对象
public LoggingConfig? Logging { get; set; }
}
[CfgSection]
public partial class DatabaseConfig
{
public string? ConnectionString { get; set; }
public int Timeout { get; set; } = 30;
}
[CfgSection]
public partial class LoggingConfig
{
public string? Level { get; set; }
public bool EnableConsole { get; set; }
}
// 对应的 JSON 配置:
// {
// ""App"": {
// ""Name"": ""MyApp"",
// ""Database"": {
// ""ConnectionString"": ""Server=localhost;..."",
// ""Timeout"": 60
// },
// ""Logging"": {
// ""Level"": ""Info"",
// ""EnableConsole"": true
// }
// }
// }
");
}
private static void ShowCollectionTypes()
{
Console.WriteLine("集合类型:");
Console.WriteLine(@"
[CfgSection(""Collections"")]
public partial class CollectionsConfig
{
// 数组
public string[]? Tags { get; set; }
public int[]? Ports { get; set; }
// List
public List? Hosts { get; set; }
// HashSet
public HashSet? AllowedOrigins { get; set; }
// Dictionary
public Dictionary? Headers { get; set; }
public Dictionary? Limits { get; set; }
}
// 对应的 JSON 配置:
// {
// ""Collections"": {
// ""Tags"": [""web"", ""api"", ""v2""],
// ""Ports"": [80, 443, 8080],
// ""Hosts"": [""host1.com"", ""host2.com""],
// ""AllowedOrigins"": [""https://example.com""],
// ""Headers"": {
// ""X-Api-Key"": ""secret"",
// ""X-Version"": ""1.0""
// },
// ""Limits"": {
// ""MaxConnections"": 100,
// ""MaxRequests"": 1000
// }
// }
// }
");
}
private static void ShowGeneratedCode()
{
Console.WriteLine("查看生成的代码:");
Console.WriteLine(@"
// 在项目文件中添加以下配置可以保留生成的源代码:
true
$(BaseIntermediateOutputPath)\GeneratedFiles
// 生成的文件将位于 obj/GeneratedFiles/ 目录下
// 生成的代码示例:
partial class DatabaseConfig
{
public static DatabaseConfig BindFrom(ICfgSection section)
{
if (section == null) throw new ArgumentNullException(nameof(section));
var result = new DatabaseConfig();
BindTo(section, result);
return result;
}
public static void BindTo(ICfgSection section, DatabaseConfig target)
{
if (section == null) throw new ArgumentNullException(nameof(section));
if (target == null) throw new ArgumentNullException(nameof(target));
// ConnectionString: string?
{
var __value = section.Get(""ConnectionString"");
if (__value != null)
{
target.ConnectionString = __value;
}
}
// Timeout: int
{
var __value = section.Get(""Timeout"");
if (__value != null)
{
var __converted = int.TryParse(__value, out var __intVal) ? __intVal : (int?)null;
if (__converted != null) target.Timeout = __converted.Value;
}
}
}
}
");
}
private static async Task DemoActualUsageAsync(string baseDir)
{
Console.WriteLine("实际演示(使用内存配置):");
// 创建一个简单的配置
var cfg = new CfgBuilder()
.AddJson(Path.Combine(baseDir, "config.json"), level: 0, writeable: false, optional: true, reloadOnChange: false)
.Build();
// 由于源生成器需要在编译时生成代码,这里只能展示概念
Console.WriteLine(@"
// 假设我们有以下配置类:
// [CfgSection(""Database"")]
// public partial class DatabaseConfig
// {
// public string? Host { get; set; }
// public int Port { get; set; }
// public string? Name { get; set; }
// }
// 使用方式:
// var dbConfig = DatabaseConfig.BindFrom(cfg.GetSection(""Database""));
// Console.WriteLine($""Host: {dbConfig.Host}"");
// Console.WriteLine($""Port: {dbConfig.Port}"");
// Console.WriteLine($""Name: {dbConfig.Name}"");
");
// 使用传统方式读取配置作为对比
var section = cfg.GetSection("Database");
Console.WriteLine("\n使用传统方式读取配置(对比):");
Console.WriteLine($" Host: {section.Get("Host") ?? "(未配置)"}");
Console.WriteLine($" Port: {section.Get("Port") ?? "(未配置)"}");
Console.WriteLine($" Name: {section.Get("Name") ?? "(未配置)"}");
Console.WriteLine("\n源生成器的优势:");
Console.WriteLine(" ✓ 零反射 - 编译时生成绑定代码");
Console.WriteLine(" ✓ Native AOT 兼容 - 完全支持 AOT 发布");
Console.WriteLine(" ✓ 编译时类型检查 - 属性名错误会在编译时报错");
Console.WriteLine(" ✓ 更好的性能 - 无运行时反射开销");
Console.WriteLine(" ✓ IntelliSense 支持 - IDE 自动补全");
await Task.CompletedTask;
}
}