| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561 |
- using System;
- using System.Collections.Immutable;
- using System.Text;
- namespace Apq.Cfg.SourceGenerator;
- /// <summary>
- /// 代码生成器,生成配置绑定代码
- /// </summary>
- internal static class CodeEmitter
- {
- /// <summary>
- /// 生成配置类的绑定代码
- /// </summary>
- public static string EmitBinderClass(ConfigClassInfo classInfo)
- {
- var sb = new StringBuilder();
- sb.AppendLine("// <auto-generated/>");
- 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();
- }
- /// <summary>
- /// 生成 BindFrom 静态方法
- /// </summary>
- private static void EmitBindFromMethod(StringBuilder sb, ConfigClassInfo classInfo, string indent)
- {
- sb.AppendLine($"{indent}/// <summary>");
- sb.AppendLine($"{indent}/// 从配置节创建并绑定配置对象(零反射)");
- sb.AppendLine($"{indent}/// </summary>");
- sb.AppendLine($"{indent}/// <param name=\"section\">配置节</param>");
- sb.AppendLine($"{indent}/// <returns>绑定后的配置对象</returns>");
- 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();
- }
- /// <summary>
- /// 生成 BindTo 静态方法
- /// </summary>
- private static void EmitBindToMethod(StringBuilder sb, ConfigClassInfo classInfo, string indent)
- {
- sb.AppendLine($"{indent}/// <summary>");
- sb.AppendLine($"{indent}/// 将配置节绑定到已有对象(零反射)");
- sb.AppendLine($"{indent}/// </summary>");
- sb.AppendLine($"{indent}/// <param name=\"section\">配置节</param>");
- sb.AppendLine($"{indent}/// <param name=\"target\">目标对象</param>");
- 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}}}");
- }
- /// <summary>
- /// 生成单个属性的绑定代码
- /// </summary>
- 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;
- }
- }
- /// <summary>
- /// 生成简单类型属性绑定
- /// </summary>
- 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();
- }
- /// <summary>
- /// 生成数组属性绑定
- /// </summary>
- 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();
- }
- /// <summary>
- /// 生成 List 属性绑定
- /// </summary>
- 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();
- }
- /// <summary>
- /// 生成 HashSet 属性绑定
- /// </summary>
- 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();
- }
- /// <summary>
- /// 生成 Dictionary 属性绑定
- /// </summary>
- 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();
- }
- /// <summary>
- /// 生成复杂对象属性绑定
- /// </summary>
- 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();
- }
- /// <summary>
- /// 生成元素绑定代码(用于数组)
- /// </summary>
- 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);");
- }
- }
- /// <summary>
- /// 生成元素绑定代码(用于 List)
- /// </summary>
- 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);");
- }
- }
- /// <summary>
- /// 生成元素绑定代码(用于 HashSet)
- /// </summary>
- 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);");
- }
- }
- /// <summary>
- /// 生成元素绑定代码(用于 Dictionary)
- /// </summary>
- 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;");
- }
- }
- /// <summary>
- /// 获取类型转换代码
- /// </summary>
- 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"
- };
- }
- /// <summary>
- /// 判断是否为简单类型名
- /// </summary>
- 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
- };
- }
- /// <summary>
- /// 生成扩展方法类
- /// </summary>
- public static string EmitExtensionsClass(ImmutableArray<ConfigClassInfo> classes)
- {
- var sb = new StringBuilder();
- sb.AppendLine("// <auto-generated/>");
- sb.AppendLine("// 此文件由 Apq.Cfg.SourceGenerator 自动生成,请勿手动修改");
- sb.AppendLine("#nullable enable");
- sb.AppendLine();
- sb.AppendLine("namespace Apq.Cfg");
- sb.AppendLine("{");
- sb.AppendLine(" /// <summary>");
- sb.AppendLine(" /// ICfgRoot 扩展方法(由源生成器生成)");
- sb.AppendLine(" /// </summary>");
- 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($" /// <summary>");
- sb.AppendLine($" /// 获取 {classInfo.ClassName} 配置(零反射)");
- sb.AppendLine($" /// </summary>");
- 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();
- }
- }
|