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(); } }