using System;
using System.Collections.Immutable;
using System.Text;
namespace Apq.Cfg.SourceGenerator;
///
/// 代码生成器,生成配置绑定代码
///
internal static class CodeEmitter
{
///
/// 生成配置类的绑定代码
///
public static string EmitBinderClass(ConfigClassInfo classInfo)
{
var sb = new StringBuilder();
sb.AppendLine("// ");
sb.AppendLine("// 此文件由 Apq.Cfg.SourceGenerator 自动生成,请勿手动修改");
sb.AppendLine("#nullable enable");
sb.AppendLine();
// 命名空间
if (!string.IsNullOrEmpty(classInfo.Namespace))
{
sb.AppendLine($"namespace {classInfo.Namespace}");
sb.AppendLine("{");
}
// partial 类
var indent = string.IsNullOrEmpty(classInfo.Namespace) ? "" : " ";
sb.AppendLine($"{indent}partial class {classInfo.ClassName}");
sb.AppendLine($"{indent}{{");
// BindFrom 静态方法
EmitBindFromMethod(sb, classInfo, indent + " ");
// BindTo 实例方法(绑定到已有实例)
EmitBindToMethod(sb, classInfo, indent + " ");
sb.AppendLine($"{indent}}}");
if (!string.IsNullOrEmpty(classInfo.Namespace))
{
sb.AppendLine("}");
}
return sb.ToString();
}
///
/// 生成 BindFrom 静态方法
///
private static void EmitBindFromMethod(StringBuilder sb, ConfigClassInfo classInfo, string indent)
{
sb.AppendLine($"{indent}/// ");
sb.AppendLine($"{indent}/// 从配置节创建并绑定配置对象(零反射)");
sb.AppendLine($"{indent}/// ");
sb.AppendLine($"{indent}/// 配置节");
sb.AppendLine($"{indent}/// 绑定后的配置对象");
sb.AppendLine($"{indent}[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]");
sb.AppendLine($"{indent}public static {classInfo.ClassName} BindFrom(global::Apq.Cfg.ICfgSection section)");
sb.AppendLine($"{indent}{{");
sb.AppendLine($"{indent} if (section == null) throw new global::System.ArgumentNullException(nameof(section));");
sb.AppendLine();
sb.AppendLine($"{indent} var result = new {classInfo.ClassName}();");
sb.AppendLine($"{indent} BindTo(section, result);");
sb.AppendLine($"{indent} return result;");
sb.AppendLine($"{indent}}}");
sb.AppendLine();
}
///
/// 生成 BindTo 静态方法
///
private static void EmitBindToMethod(StringBuilder sb, ConfigClassInfo classInfo, string indent)
{
sb.AppendLine($"{indent}/// ");
sb.AppendLine($"{indent}/// 将配置节绑定到已有对象(零反射)");
sb.AppendLine($"{indent}/// ");
sb.AppendLine($"{indent}/// 配置节");
sb.AppendLine($"{indent}/// 目标对象");
sb.AppendLine($"{indent}[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]");
sb.AppendLine($"{indent}public static void BindTo(global::Apq.Cfg.ICfgSection section, {classInfo.ClassName} target)");
sb.AppendLine($"{indent}{{");
sb.AppendLine($"{indent} if (section == null) throw new global::System.ArgumentNullException(nameof(section));");
sb.AppendLine($"{indent} if (target == null) throw new global::System.ArgumentNullException(nameof(target));");
sb.AppendLine();
foreach (var prop in classInfo.Properties)
{
EmitPropertyBinding(sb, prop, indent + " ");
}
sb.AppendLine($"{indent}}}");
}
///
/// 生成单个属性的绑定代码
///
private static void EmitPropertyBinding(StringBuilder sb, PropertyInfo prop, string indent)
{
switch (prop.TypeKind)
{
case TypeKind.Simple:
EmitSimplePropertyBinding(sb, prop, indent);
break;
case TypeKind.Array:
EmitArrayPropertyBinding(sb, prop, indent);
break;
case TypeKind.List:
EmitListPropertyBinding(sb, prop, indent);
break;
case TypeKind.HashSet:
EmitHashSetPropertyBinding(sb, prop, indent);
break;
case TypeKind.Dictionary:
EmitDictionaryPropertyBinding(sb, prop, indent);
break;
case TypeKind.Complex:
EmitComplexPropertyBinding(sb, prop, indent);
break;
default:
sb.AppendLine($"{indent}// TODO: 不支持的类型 {prop.TypeName} for {prop.Name}");
break;
}
}
///
/// 生成简单类型属性绑定
///
private static void EmitSimplePropertyBinding(StringBuilder sb, PropertyInfo prop, string indent)
{
sb.AppendLine($"{indent}// {prop.Name}: {prop.TypeName}");
sb.AppendLine($"{indent}{{");
sb.AppendLine($"{indent} var __value = section.Get(\"{prop.Name}\");");
sb.AppendLine($"{indent} if (__value != null)");
sb.AppendLine($"{indent} {{");
// 根据类型生成转换代码
var baseType = prop.TypeName.TrimEnd('?');
var convertCode = GetConvertCode(prop.TypeName, "__value");
// string 和 Uri 是引用类型,不需要 .Value
if (baseType == "string" || baseType == "System.String")
{
sb.AppendLine($"{indent} target.{prop.Name} = {convertCode};");
}
else if (baseType == "System.Uri")
{
sb.AppendLine($"{indent} target.{prop.Name} = {convertCode};");
}
else if (prop.IsNullable)
{
sb.AppendLine($"{indent} target.{prop.Name} = {convertCode};");
}
else
{
sb.AppendLine($"{indent} var __converted = {convertCode};");
sb.AppendLine($"{indent} if (__converted != null) target.{prop.Name} = __converted.Value;");
}
sb.AppendLine($"{indent} }}");
sb.AppendLine($"{indent}}}");
sb.AppendLine();
}
///
/// 生成数组属性绑定
///
private static void EmitArrayPropertyBinding(StringBuilder sb, PropertyInfo prop, string indent)
{
var elementType = prop.ElementTypeName ?? "object";
sb.AppendLine($"{indent}// {prop.Name}: {prop.TypeName}");
sb.AppendLine($"{indent}{{");
sb.AppendLine($"{indent} var __childSection = section.GetSection(\"{prop.Name}\");");
sb.AppendLine($"{indent} var __keys = __childSection.GetChildKeys()");
sb.AppendLine($"{indent} .Where(k => int.TryParse(k, out _))");
sb.AppendLine($"{indent} .OrderBy(k => int.Parse(k))");
sb.AppendLine($"{indent} .ToList();");
sb.AppendLine($"{indent} if (__keys.Count > 0)");
sb.AppendLine($"{indent} {{");
sb.AppendLine($"{indent} var __array = new {elementType}[__keys.Count];");
sb.AppendLine($"{indent} for (int __i = 0; __i < __keys.Count; __i++)");
sb.AppendLine($"{indent} {{");
EmitElementBinding(sb, elementType, "__childSection", "__keys[__i]", $"__array[__i]", indent + " ");
sb.AppendLine($"{indent} }}");
sb.AppendLine($"{indent} target.{prop.Name} = __array;");
sb.AppendLine($"{indent} }}");
sb.AppendLine($"{indent}}}");
sb.AppendLine();
}
///
/// 生成 List 属性绑定
///
private static void EmitListPropertyBinding(StringBuilder sb, PropertyInfo prop, string indent)
{
var elementType = prop.ElementTypeName ?? "object";
sb.AppendLine($"{indent}// {prop.Name}: {prop.TypeName}");
sb.AppendLine($"{indent}{{");
sb.AppendLine($"{indent} var __childSection = section.GetSection(\"{prop.Name}\");");
sb.AppendLine($"{indent} var __keys = __childSection.GetChildKeys()");
sb.AppendLine($"{indent} .Where(k => int.TryParse(k, out _))");
sb.AppendLine($"{indent} .OrderBy(k => int.Parse(k))");
sb.AppendLine($"{indent} .ToList();");
sb.AppendLine($"{indent} if (__keys.Count > 0)");
sb.AppendLine($"{indent} {{");
sb.AppendLine($"{indent} var __list = new global::System.Collections.Generic.List<{elementType}>(__keys.Count);");
sb.AppendLine($"{indent} foreach (var __key in __keys)");
sb.AppendLine($"{indent} {{");
EmitElementBindingForCollection(sb, elementType, "__childSection", "__key", "__list", indent + " ");
sb.AppendLine($"{indent} }}");
sb.AppendLine($"{indent} target.{prop.Name} = __list;");
sb.AppendLine($"{indent} }}");
sb.AppendLine($"{indent}}}");
sb.AppendLine();
}
///
/// 生成 HashSet 属性绑定
///
private static void EmitHashSetPropertyBinding(StringBuilder sb, PropertyInfo prop, string indent)
{
var elementType = prop.ElementTypeName ?? "object";
sb.AppendLine($"{indent}// {prop.Name}: {prop.TypeName}");
sb.AppendLine($"{indent}{{");
sb.AppendLine($"{indent} var __childSection = section.GetSection(\"{prop.Name}\");");
sb.AppendLine($"{indent} var __keys = __childSection.GetChildKeys()");
sb.AppendLine($"{indent} .Where(k => int.TryParse(k, out _))");
sb.AppendLine($"{indent} .OrderBy(k => int.Parse(k))");
sb.AppendLine($"{indent} .ToList();");
sb.AppendLine($"{indent} if (__keys.Count > 0)");
sb.AppendLine($"{indent} {{");
sb.AppendLine($"{indent} var __set = new global::System.Collections.Generic.HashSet<{elementType}>();");
sb.AppendLine($"{indent} foreach (var __key in __keys)");
sb.AppendLine($"{indent} {{");
EmitElementBindingForSet(sb, elementType, "__childSection", "__key", "__set", indent + " ");
sb.AppendLine($"{indent} }}");
sb.AppendLine($"{indent} target.{prop.Name} = __set;");
sb.AppendLine($"{indent} }}");
sb.AppendLine($"{indent}}}");
sb.AppendLine();
}
///
/// 生成 Dictionary 属性绑定
///
private static void EmitDictionaryPropertyBinding(StringBuilder sb, PropertyInfo prop, string indent)
{
var keyType = prop.KeyTypeName ?? "string";
var valueType = prop.ElementTypeName ?? "object";
sb.AppendLine($"{indent}// {prop.Name}: {prop.TypeName}");
sb.AppendLine($"{indent}{{");
sb.AppendLine($"{indent} var __childSection = section.GetSection(\"{prop.Name}\");");
sb.AppendLine($"{indent} var __keys = __childSection.GetChildKeys().ToList();");
sb.AppendLine($"{indent} if (__keys.Count > 0)");
sb.AppendLine($"{indent} {{");
sb.AppendLine($"{indent} var __dict = new global::System.Collections.Generic.Dictionary<{keyType}, {valueType}>();");
sb.AppendLine($"{indent} foreach (var __key in __keys)");
sb.AppendLine($"{indent} {{");
// 键转换
if (keyType == "string")
{
sb.AppendLine($"{indent} var __dictKey = __key;");
}
else
{
var keyConvert = GetConvertCode(keyType, "__key");
sb.AppendLine($"{indent} var __dictKeyNullable = {keyConvert};");
sb.AppendLine($"{indent} if (__dictKeyNullable == null) continue;");
sb.AppendLine($"{indent} var __dictKey = __dictKeyNullable.Value;");
}
EmitElementBindingForDictionary(sb, valueType, "__childSection", "__key", "__dict", "__dictKey", indent + " ");
sb.AppendLine($"{indent} }}");
sb.AppendLine($"{indent} target.{prop.Name} = __dict;");
sb.AppendLine($"{indent} }}");
sb.AppendLine($"{indent}}}");
sb.AppendLine();
}
///
/// 生成复杂对象属性绑定
///
private static void EmitComplexPropertyBinding(StringBuilder sb, PropertyInfo prop, string indent)
{
// 获取全局限定的类型名,移除可空标记
var baseTypeName = prop.TypeName.TrimEnd('?');
var globalTypeName = baseTypeName.StartsWith("global::") ? baseTypeName : $"global::{baseTypeName}";
sb.AppendLine($"{indent}// {prop.Name}: {prop.TypeName} (复杂对象)");
sb.AppendLine($"{indent}{{");
sb.AppendLine($"{indent} var __childSection = section.GetSection(\"{prop.Name}\");");
sb.AppendLine($"{indent} var __childKeys = __childSection.GetChildKeys().ToList();");
sb.AppendLine($"{indent} if (__childKeys.Count > 0)");
sb.AppendLine($"{indent} {{");
// 使用生成的 BindFrom 方法
sb.AppendLine($"{indent} target.{prop.Name} = {globalTypeName}.BindFrom(__childSection);");
sb.AppendLine($"{indent} }}");
sb.AppendLine($"{indent}}}");
sb.AppendLine();
}
///
/// 生成元素绑定代码(用于数组)
///
private static void EmitElementBinding(StringBuilder sb, string elementType, string sectionVar, string keyVar, string targetVar, string indent)
{
if (IsSimpleTypeName(elementType))
{
var baseType = elementType.TrimEnd('?');
sb.AppendLine($"{indent}var __elemValue = {sectionVar}.Get({keyVar});");
sb.AppendLine($"{indent}if (__elemValue != null)");
sb.AppendLine($"{indent}{{");
var convertCode = GetConvertCode(elementType, "__elemValue");
// string 是引用类型,直接赋值
if (baseType == "string" || baseType == "System.String")
{
sb.AppendLine($"{indent} {targetVar} = {convertCode};");
}
else
{
sb.AppendLine($"{indent} var __converted = {convertCode};");
sb.AppendLine($"{indent} if (__converted != null) {targetVar} = __converted.Value;");
}
sb.AppendLine($"{indent}}}");
}
else
{
var globalType = elementType.StartsWith("global::") ? elementType : $"global::{elementType}";
sb.AppendLine($"{indent}var __elemSection = {sectionVar}.GetSection({keyVar});");
sb.AppendLine($"{indent}{targetVar} = {globalType}.BindFrom(__elemSection);");
}
}
///
/// 生成元素绑定代码(用于 List)
///
private static void EmitElementBindingForCollection(StringBuilder sb, string elementType, string sectionVar, string keyVar, string listVar, string indent)
{
if (IsSimpleTypeName(elementType))
{
var baseType = elementType.TrimEnd('?');
sb.AppendLine($"{indent}var __elemValue = {sectionVar}.Get({keyVar});");
sb.AppendLine($"{indent}if (__elemValue != null)");
sb.AppendLine($"{indent}{{");
var convertCode = GetConvertCode(elementType, "__elemValue");
// string 是引用类型,直接添加
if (baseType == "string" || baseType == "System.String")
{
sb.AppendLine($"{indent} {listVar}.Add({convertCode});");
}
else
{
sb.AppendLine($"{indent} var __converted = {convertCode};");
sb.AppendLine($"{indent} if (__converted != null) {listVar}.Add(__converted.Value);");
}
sb.AppendLine($"{indent}}}");
}
else
{
var globalType = elementType.StartsWith("global::") ? elementType : $"global::{elementType}";
sb.AppendLine($"{indent}var __elemSection = {sectionVar}.GetSection({keyVar});");
sb.AppendLine($"{indent}var __elem = {globalType}.BindFrom(__elemSection);");
sb.AppendLine($"{indent}if (__elem != null) {listVar}.Add(__elem);");
}
}
///
/// 生成元素绑定代码(用于 HashSet)
///
private static void EmitElementBindingForSet(StringBuilder sb, string elementType, string sectionVar, string keyVar, string setVar, string indent)
{
if (IsSimpleTypeName(elementType))
{
var baseType = elementType.TrimEnd('?');
sb.AppendLine($"{indent}var __elemValue = {sectionVar}.Get({keyVar});");
sb.AppendLine($"{indent}if (__elemValue != null)");
sb.AppendLine($"{indent}{{");
var convertCode = GetConvertCode(elementType, "__elemValue");
// string 是引用类型,直接添加
if (baseType == "string" || baseType == "System.String")
{
sb.AppendLine($"{indent} {setVar}.Add({convertCode});");
}
else
{
sb.AppendLine($"{indent} var __converted = {convertCode};");
sb.AppendLine($"{indent} if (__converted != null) {setVar}.Add(__converted.Value);");
}
sb.AppendLine($"{indent}}}");
}
else
{
var globalType = elementType.StartsWith("global::") ? elementType : $"global::{elementType}";
sb.AppendLine($"{indent}var __elemSection = {sectionVar}.GetSection({keyVar});");
sb.AppendLine($"{indent}var __elem = {globalType}.BindFrom(__elemSection);");
sb.AppendLine($"{indent}if (__elem != null) {setVar}.Add(__elem);");
}
}
///
/// 生成元素绑定代码(用于 Dictionary)
///
private static void EmitElementBindingForDictionary(StringBuilder sb, string valueType, string sectionVar, string keyVar, string dictVar, string dictKeyVar, string indent)
{
if (IsSimpleTypeName(valueType))
{
var baseType = valueType.TrimEnd('?');
sb.AppendLine($"{indent}var __elemValue = {sectionVar}.Get({keyVar});");
sb.AppendLine($"{indent}if (__elemValue != null)");
sb.AppendLine($"{indent}{{");
var convertCode = GetConvertCode(valueType, "__elemValue");
// string 是引用类型,直接赋值
if (baseType == "string" || baseType == "System.String")
{
sb.AppendLine($"{indent} {dictVar}[{dictKeyVar}] = {convertCode};");
}
else
{
sb.AppendLine($"{indent} var __converted = {convertCode};");
sb.AppendLine($"{indent} if (__converted != null) {dictVar}[{dictKeyVar}] = __converted.Value;");
}
sb.AppendLine($"{indent}}}");
}
else
{
var globalType = valueType.StartsWith("global::") ? valueType : $"global::{valueType}";
sb.AppendLine($"{indent}var __elemSection = {sectionVar}.GetSection({keyVar});");
sb.AppendLine($"{indent}var __elem = {globalType}.BindFrom(__elemSection);");
sb.AppendLine($"{indent}if (__elem != null) {dictVar}[{dictKeyVar}] = __elem;");
}
}
///
/// 获取类型转换代码
///
private static string GetConvertCode(string typeName, string valueVar)
{
// 移除可空标记
var baseType = typeName.TrimEnd('?');
return baseType switch
{
"string" => valueVar,
"int" or "System.Int32" => $"int.TryParse({valueVar}, out var __intVal) ? __intVal : (int?)null",
"long" or "System.Int64" => $"long.TryParse({valueVar}, out var __longVal) ? __longVal : (long?)null",
"short" or "System.Int16" => $"short.TryParse({valueVar}, out var __shortVal) ? __shortVal : (short?)null",
"byte" or "System.Byte" => $"byte.TryParse({valueVar}, out var __byteVal) ? __byteVal : (byte?)null",
"sbyte" or "System.SByte" => $"sbyte.TryParse({valueVar}, out var __sbyteVal) ? __sbyteVal : (sbyte?)null",
"uint" or "System.UInt32" => $"uint.TryParse({valueVar}, out var __uintVal) ? __uintVal : (uint?)null",
"ulong" or "System.UInt64" => $"ulong.TryParse({valueVar}, out var __ulongVal) ? __ulongVal : (ulong?)null",
"ushort" or "System.UInt16" => $"ushort.TryParse({valueVar}, out var __ushortVal) ? __ushortVal : (ushort?)null",
"float" or "System.Single" => $"float.TryParse({valueVar}, global::System.Globalization.NumberStyles.Float, global::System.Globalization.CultureInfo.InvariantCulture, out var __floatVal) ? __floatVal : (float?)null",
"double" or "System.Double" => $"double.TryParse({valueVar}, global::System.Globalization.NumberStyles.Float, global::System.Globalization.CultureInfo.InvariantCulture, out var __doubleVal) ? __doubleVal : (double?)null",
"decimal" or "System.Decimal" => $"decimal.TryParse({valueVar}, global::System.Globalization.NumberStyles.Number, global::System.Globalization.CultureInfo.InvariantCulture, out var __decimalVal) ? __decimalVal : (decimal?)null",
"bool" or "System.Boolean" => $"bool.TryParse({valueVar}, out var __boolVal) ? __boolVal : (bool?)null",
"char" or "System.Char" => $"({valueVar}.Length > 0 ? {valueVar}[0] : (char?)null)",
"System.DateTime" => $"global::System.DateTime.TryParse({valueVar}, out var __dtVal) ? __dtVal : (global::System.DateTime?)null",
"System.DateTimeOffset" => $"global::System.DateTimeOffset.TryParse({valueVar}, out var __dtoVal) ? __dtoVal : (global::System.DateTimeOffset?)null",
"System.TimeSpan" => $"global::System.TimeSpan.TryParse({valueVar}, out var __tsVal) ? __tsVal : (global::System.TimeSpan?)null",
"System.Guid" => $"global::System.Guid.TryParse({valueVar}, out var __guidVal) ? __guidVal : (global::System.Guid?)null",
"System.DateOnly" => $"global::System.DateOnly.TryParse({valueVar}, out var __doVal) ? __doVal : (global::System.DateOnly?)null",
"System.TimeOnly" => $"global::System.TimeOnly.TryParse({valueVar}, out var __toVal) ? __toVal : (global::System.TimeOnly?)null",
"System.Uri" => $"global::System.Uri.TryCreate({valueVar}, global::System.UriKind.RelativeOrAbsolute, out var __uriVal) ? __uriVal : null",
_ when baseType.Contains(".") => $"global::System.Enum.TryParse<{baseType}>({valueVar}, true, out var __enumVal) ? __enumVal : ({baseType}?)null",
_ => $"global::System.Enum.TryParse<{baseType}>({valueVar}, true, out var __enumVal) ? __enumVal : ({baseType}?)null"
};
}
///
/// 判断是否为简单类型名
///
private static bool IsSimpleTypeName(string typeName)
{
var baseType = typeName.TrimEnd('?');
return baseType switch
{
"string" or "int" or "long" or "short" or "byte" or "sbyte" or
"uint" or "ulong" or "ushort" or "float" or "double" or "decimal" or
"bool" or "char" or
"System.String" or "System.Int32" or "System.Int64" or "System.Int16" or
"System.Byte" or "System.SByte" or "System.UInt32" or "System.UInt64" or
"System.UInt16" or "System.Single" or "System.Double" or "System.Decimal" or
"System.Boolean" or "System.Char" or
"System.DateTime" or "System.DateTimeOffset" or "System.TimeSpan" or
"System.Guid" or "System.Uri" or "System.DateOnly" or "System.TimeOnly" => true,
_ => false
};
}
///
/// 生成扩展方法类
///
public static string EmitExtensionsClass(ImmutableArray classes)
{
var sb = new StringBuilder();
sb.AppendLine("// ");
sb.AppendLine("// 此文件由 Apq.Cfg.SourceGenerator 自动生成,请勿手动修改");
sb.AppendLine("#nullable enable");
sb.AppendLine();
sb.AppendLine("namespace Apq.Cfg");
sb.AppendLine("{");
sb.AppendLine(" /// ");
sb.AppendLine(" /// ICfgRoot 扩展方法(由源生成器生成)");
sb.AppendLine(" /// ");
sb.AppendLine(" [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]");
sb.AppendLine(" internal static class CfgRootGeneratedExtensions");
sb.AppendLine(" {");
foreach (var classInfo in classes)
{
if (!classInfo.GenerateExtension)
continue;
var methodName = $"Get{classInfo.ClassName}";
var sectionPath = classInfo.SectionPath;
sb.AppendLine($" /// ");
sb.AppendLine($" /// 获取 {classInfo.ClassName} 配置(零反射)");
sb.AppendLine($" /// ");
sb.AppendLine($" public static {classInfo.FullTypeName} {methodName}(this global::Apq.Cfg.ICfgRoot cfg)");
sb.AppendLine($" {{");
sb.AppendLine($" return {classInfo.FullTypeName}.BindFrom(cfg.GetSection(\"{sectionPath}\"));");
sb.AppendLine($" }}");
sb.AppendLine();
}
sb.AppendLine(" }");
sb.AppendLine("}");
return sb.ToString();
}
}