2025-05-08 17:21:20 +08:00
|
|
|
|
using JiShe.CollectBus.Analyzers.Shared;
|
|
|
|
|
|
using Microsoft.CodeAnalysis;
|
2025-04-28 14:07:51 +08:00
|
|
|
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
2025-05-07 10:15:45 +08:00
|
|
|
|
using System;
|
2025-04-28 14:07:51 +08:00
|
|
|
|
using System.Collections.Generic;
|
2025-05-08 11:17:43 +08:00
|
|
|
|
using System.Collections.Immutable;
|
2025-04-28 14:07:51 +08:00
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using System.Text;
|
|
|
|
|
|
|
|
|
|
|
|
namespace JiShe.CollectBus.IncrementalGenerator
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
2025-05-07 10:15:45 +08:00
|
|
|
|
/// 复杂类型增量源生成器
|
2025-04-28 14:07:51 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
[Generator(LanguageNames.CSharp)]
|
2025-04-29 09:14:58 +08:00
|
|
|
|
public class ComplexTypeSourceAnalyzers : IIncrementalGenerator
|
2025-04-28 14:07:51 +08:00
|
|
|
|
{
|
2025-04-29 10:02:10 +08:00
|
|
|
|
private const string AttributeFullName = "JiShe.CollectBus.Analyzers.Shared.SourceAnalyzersAttribute";
|
2025-04-28 14:07:51 +08:00
|
|
|
|
|
|
|
|
|
|
public void Initialize(IncrementalGeneratorInitializationContext context)
|
|
|
|
|
|
{
|
2025-04-28 22:35:19 +08:00
|
|
|
|
//Debugger.Launch();
|
2025-04-28 14:07:51 +08:00
|
|
|
|
|
2025-05-06 23:46:12 +08:00
|
|
|
|
// 步骤1:筛选带有 [SourceAnalyzers] 的类
|
2025-04-28 14:07:51 +08:00
|
|
|
|
var classDeclarations = context.SyntaxProvider
|
|
|
|
|
|
.CreateSyntaxProvider(
|
|
|
|
|
|
predicate: static (s, _) => IsClassWithAttribute(s),
|
|
|
|
|
|
transform: static (ctx, _) => GetClassDeclaration(ctx))
|
|
|
|
|
|
.Where(static c => c is not null);
|
|
|
|
|
|
|
|
|
|
|
|
// 步骤2:合并编译信息
|
|
|
|
|
|
var compilationAndClasses = context.CompilationProvider.Combine(classDeclarations.Collect());
|
|
|
|
|
|
|
|
|
|
|
|
context.RegisterSourceOutput(compilationAndClasses, (spc, source) =>
|
2025-05-07 10:15:45 +08:00
|
|
|
|
GenerateCode(source.Left, source.Right!, spc));
|
2025-04-28 14:07:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static bool IsClassWithAttribute(SyntaxNode node) => node is ClassDeclarationSyntax cds && cds.AttributeLists.Count > 0;
|
2025-05-07 10:15:45 +08:00
|
|
|
|
|
2025-04-28 22:35:19 +08:00
|
|
|
|
private static ClassDeclarationSyntax GetClassDeclaration(GeneratorSyntaxContext context)
|
2025-04-28 14:07:51 +08:00
|
|
|
|
{
|
|
|
|
|
|
var classDecl = (ClassDeclarationSyntax)context.Node;
|
2025-05-08 17:21:20 +08:00
|
|
|
|
var semanticModel = context.SemanticModel;
|
2025-04-28 14:07:51 +08:00
|
|
|
|
|
2025-05-08 17:21:20 +08:00
|
|
|
|
// 获取类符号
|
|
|
|
|
|
var classSymbol = semanticModel.GetDeclaredSymbol(classDecl) as INamedTypeSymbol;
|
|
|
|
|
|
if (classSymbol == null) return null;
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否包含 SourceAnalyzers 特性
|
|
|
|
|
|
var sourceAnalyzerAttr = classSymbol.GetAttributes().FirstOrDefault(attr => attr.AttributeClass?.ToDisplayString() == AttributeFullName);
|
|
|
|
|
|
|
|
|
|
|
|
// 必须包含 EntityType 参数
|
|
|
|
|
|
if (sourceAnalyzerAttr == null ||
|
|
|
|
|
|
sourceAnalyzerAttr.ConstructorArguments.Length == 0)
|
2025-04-28 14:07:51 +08:00
|
|
|
|
{
|
2025-05-08 17:21:20 +08:00
|
|
|
|
return null;
|
2025-04-28 14:07:51 +08:00
|
|
|
|
}
|
2025-05-08 17:21:20 +08:00
|
|
|
|
|
|
|
|
|
|
return classDecl;
|
|
|
|
|
|
|
|
|
|
|
|
//var classDecl = (ClassDeclarationSyntax)context.Node;
|
|
|
|
|
|
//var attributeType = context.SemanticModel.Compilation.GetTypeByMetadataName(AttributeFullName);
|
|
|
|
|
|
|
|
|
|
|
|
//foreach (var attribute in classDecl.AttributeLists.SelectMany(al => al.Attributes))
|
|
|
|
|
|
//{
|
|
|
|
|
|
// var symbol = context.SemanticModel.GetSymbolInfo(attribute).Symbol;
|
|
|
|
|
|
// if (symbol is IMethodSymbol ctor &&
|
|
|
|
|
|
// SymbolEqualityComparer.Default.Equals(ctor.ContainingType, attributeType))
|
|
|
|
|
|
// {
|
|
|
|
|
|
// return classDecl;
|
|
|
|
|
|
// }
|
|
|
|
|
|
//}
|
|
|
|
|
|
//return null;
|
2025-04-28 14:07:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-28 17:45:00 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 递归获取所有层级的属性
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="classSymbol"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
private static IEnumerable<IPropertySymbol> GetAllPropertiesInHierarchy(INamedTypeSymbol classSymbol)
|
|
|
|
|
|
{
|
|
|
|
|
|
var currentSymbol = classSymbol;
|
|
|
|
|
|
while (currentSymbol != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var prop in currentSymbol.GetMembers().OfType<IPropertySymbol>())
|
|
|
|
|
|
{
|
|
|
|
|
|
yield return prop;
|
|
|
|
|
|
}
|
|
|
|
|
|
currentSymbol = currentSymbol.BaseType; // 向上遍历基类
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-05-06 23:46:12 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 生成代码
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="compilation"></param>
|
|
|
|
|
|
/// <param name="classes"></param>
|
|
|
|
|
|
/// <param name="context"></param>
|
2025-04-28 14:07:51 +08:00
|
|
|
|
private static void GenerateCode(
|
|
|
|
|
|
Compilation compilation,
|
|
|
|
|
|
IEnumerable<ClassDeclarationSyntax> classes,
|
|
|
|
|
|
SourceProductionContext context)
|
|
|
|
|
|
{
|
|
|
|
|
|
var processedTypes = new HashSet<ITypeSymbol>(SymbolEqualityComparer.Default);
|
2025-05-06 23:46:12 +08:00
|
|
|
|
|
2025-04-28 16:37:31 +08:00
|
|
|
|
if (!classes.Any())
|
|
|
|
|
|
{
|
|
|
|
|
|
context.ReportDiagnostic(Diagnostic.Create(
|
2025-05-06 23:46:12 +08:00
|
|
|
|
new DiagnosticDescriptor("GEN002", "没有目标类",
|
|
|
|
|
|
"没有找到SourceAnalyzers标记的类", "Debug", DiagnosticSeverity.Warning, true),
|
2025-04-28 16:37:31 +08:00
|
|
|
|
Location.None));
|
|
|
|
|
|
}
|
2025-04-28 14:07:51 +08:00
|
|
|
|
|
|
|
|
|
|
foreach (var classDecl in classes.Distinct())
|
|
|
|
|
|
{
|
|
|
|
|
|
var model = compilation.GetSemanticModel(classDecl.SyntaxTree);
|
|
|
|
|
|
var classSymbol = model.GetDeclaredSymbol(classDecl) as INamedTypeSymbol;
|
|
|
|
|
|
|
2025-04-28 16:37:31 +08:00
|
|
|
|
if (classSymbol == null || !processedTypes.Add(classSymbol))
|
|
|
|
|
|
{
|
|
|
|
|
|
context.ReportDiagnostic(Diagnostic.Create(
|
2025-05-06 23:46:12 +08:00
|
|
|
|
new DiagnosticDescriptor("GEN003", "无效符号",
|
|
|
|
|
|
$"类名称为{classDecl.Identifier.Text} 符号为空", "Error", DiagnosticSeverity.Error, true),
|
2025-04-28 16:37:31 +08:00
|
|
|
|
Location.None));
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
2025-05-08 11:17:43 +08:00
|
|
|
|
|
2025-05-07 10:15:45 +08:00
|
|
|
|
var code3 = BuildAccessorsForSourceEntity(classSymbol, compilation, processedTypes);
|
2025-05-06 23:46:12 +08:00
|
|
|
|
context.AddSource($"{classSymbol.Name}Accessor.g.cs", code3);
|
2025-04-28 14:07:51 +08:00
|
|
|
|
}
|
2025-05-06 23:46:12 +08:00
|
|
|
|
|
|
|
|
|
|
// 生成工厂注册代码
|
|
|
|
|
|
context.AddSource("SourceEntityAccessorFactory.g.cs", BuildFactoryCode());
|
2025-04-28 14:07:51 +08:00
|
|
|
|
}
|
2025-05-08 11:17:43 +08:00
|
|
|
|
|
2025-05-06 23:46:12 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取泛型参数
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="symbol"></param>
|
|
|
|
|
|
/// <returns></returns>
|
2025-04-28 16:37:31 +08:00
|
|
|
|
public static string GetGenericParams(INamedTypeSymbol symbol)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!symbol.IsGenericType) return "";
|
|
|
|
|
|
var parameters = symbol.TypeParameters.Select(t => t.Name);
|
|
|
|
|
|
return $"<{string.Join(", ", parameters)}>";
|
|
|
|
|
|
}
|
2025-05-08 11:17:43 +08:00
|
|
|
|
|
|
|
|
|
|
|
2025-05-06 23:46:12 +08:00
|
|
|
|
/// <summary>
|
2025-05-07 16:37:26 +08:00
|
|
|
|
/// 生成标准属性的访问器
|
2025-05-06 23:46:12 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="prop"></param>
|
2025-05-07 16:37:26 +08:00
|
|
|
|
/// <param name="propType"></param>
|
2025-05-06 23:46:12 +08:00
|
|
|
|
/// <param name="code"></param>
|
2025-05-07 16:37:26 +08:00
|
|
|
|
private static void GenerateStandardAccessors(IPropertySymbol prop, INamedTypeSymbol propType, StringBuilder code)
|
2025-04-28 14:07:51 +08:00
|
|
|
|
{
|
2025-05-07 16:37:26 +08:00
|
|
|
|
var parentType = prop.ContainingType.ToDisplayString();
|
|
|
|
|
|
code.AppendLine($" public static {propType.ToDisplayString()} Get{prop.Name}({parentType} obj) => obj.{prop.Name};");
|
2025-04-28 14:07:51 +08:00
|
|
|
|
|
2025-05-07 16:37:26 +08:00
|
|
|
|
if (prop.SetMethod != null)
|
2025-04-28 14:07:51 +08:00
|
|
|
|
{
|
2025-05-07 16:37:26 +08:00
|
|
|
|
code.AppendLine($" public static void Set{prop.Name}({parentType} obj, {propType.ToDisplayString()} value) => obj.{prop.Name} = value;");
|
2025-04-28 14:07:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-05-08 11:17:43 +08:00
|
|
|
|
|
2025-04-28 14:07:51 +08:00
|
|
|
|
|
2025-05-06 23:46:12 +08:00
|
|
|
|
/// <summary>
|
2025-05-07 16:37:26 +08:00
|
|
|
|
/// 构建实体访问器代码(支持泛型)
|
2025-05-06 23:46:12 +08:00
|
|
|
|
/// </summary>
|
2025-05-07 16:37:26 +08:00
|
|
|
|
private static string BuildAccessorsForSourceEntity(
|
|
|
|
|
|
INamedTypeSymbol classSymbol,
|
|
|
|
|
|
Compilation compilation,
|
|
|
|
|
|
HashSet<ITypeSymbol> processedTypes)
|
2025-04-28 14:07:51 +08:00
|
|
|
|
{
|
2025-05-08 17:21:20 +08:00
|
|
|
|
// 获取 SourceAnalyzers 特性的 EntityType 参数
|
|
|
|
|
|
var sourceAnalyzerAttr = classSymbol.GetAttributes()
|
|
|
|
|
|
.FirstOrDefault(attr =>
|
|
|
|
|
|
attr.AttributeClass?.ToDisplayString() == AttributeFullName);
|
|
|
|
|
|
|
|
|
|
|
|
// 解析 EntityType 枚举值
|
|
|
|
|
|
string entityTypeValue = "EntityTypeEnum.Other"; // 默认值
|
|
|
|
|
|
if (sourceAnalyzerAttr != null &&
|
|
|
|
|
|
sourceAnalyzerAttr.ConstructorArguments.Length > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
var arg = sourceAnalyzerAttr.ConstructorArguments[0];
|
|
|
|
|
|
if (arg.Kind == TypedConstantKind.Enum &&
|
|
|
|
|
|
arg.Type is INamedTypeSymbol enumType)
|
|
|
|
|
|
{
|
|
|
|
|
|
int enumValue = (int)arg.Value!;
|
|
|
|
|
|
entityTypeValue = GetEnumMemberName(enumType, enumValue);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-05-07 16:37:26 +08:00
|
|
|
|
var code = new StringBuilder();
|
|
|
|
|
|
code.AppendLine("// <auto-generated/>");
|
|
|
|
|
|
code.AppendLine("#nullable enable");
|
|
|
|
|
|
code.AppendLine("using System;");
|
2025-05-07 17:27:37 +08:00
|
|
|
|
code.AppendLine("using System.Reflection;");
|
2025-05-07 16:37:26 +08:00
|
|
|
|
code.AppendLine("using System.Collections.Generic;");
|
|
|
|
|
|
code.AppendLine("using JiShe.CollectBus.Analyzers.Shared;");
|
|
|
|
|
|
code.AppendLine($"namespace {classSymbol.ContainingNamespace.ToDisplayString()};");
|
|
|
|
|
|
code.AppendLine();
|
2025-04-28 14:07:51 +08:00
|
|
|
|
|
2025-05-07 17:20:10 +08:00
|
|
|
|
// 处理泛型类型名称
|
|
|
|
|
|
var accessibility = classSymbol.DeclaredAccessibility switch
|
|
|
|
|
|
{
|
|
|
|
|
|
Accessibility.Public => "public",
|
|
|
|
|
|
_ => "internal"
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-05-07 16:37:26 +08:00
|
|
|
|
var genericParams = classSymbol.IsGenericType
|
|
|
|
|
|
? $"<{string.Join(", ", classSymbol.TypeParameters.Select(t => t.Name))}>"
|
|
|
|
|
|
: "";
|
2025-04-28 14:07:51 +08:00
|
|
|
|
|
2025-05-07 16:37:26 +08:00
|
|
|
|
code.AppendLine(
|
2025-05-07 17:20:10 +08:00
|
|
|
|
$"{accessibility} sealed class {classSymbol.Name}Accessor{genericParams} " + // 保留泛型参数
|
2025-05-07 16:37:26 +08:00
|
|
|
|
$": ISourceEntityAccessor<{classSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}>");
|
2025-04-28 14:07:51 +08:00
|
|
|
|
|
2025-05-07 16:37:26 +08:00
|
|
|
|
code.AppendLine("{");
|
2025-05-08 11:17:43 +08:00
|
|
|
|
|
2025-05-07 16:37:26 +08:00
|
|
|
|
var propList = GetAllPropertiesInHierarchy(classSymbol);
|
|
|
|
|
|
|
2025-05-08 14:42:13 +08:00
|
|
|
|
//类名称
|
|
|
|
|
|
code.AppendLine($" public string EntityName {{get;}} = \"{classSymbol.Name}\";");
|
2025-05-08 17:21:20 +08:00
|
|
|
|
// 添加 EntityType 属性
|
|
|
|
|
|
code.AppendLine($" public EntityTypeEnum? EntityType {{ get; }} = {entityTypeValue};");
|
2025-05-09 17:54:52 +08:00
|
|
|
|
|
2025-05-07 16:37:26 +08:00
|
|
|
|
foreach (var prop in propList)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 安全类型转换
|
|
|
|
|
|
if (prop.Type is not ITypeSymbol propType) continue;
|
2025-05-08 17:21:20 +08:00
|
|
|
|
|
2025-05-08 11:17:43 +08:00
|
|
|
|
if (propType is INamedTypeSymbol namedType)
|
2025-05-07 16:37:26 +08:00
|
|
|
|
{
|
2025-05-08 11:17:43 +08:00
|
|
|
|
GenerateStandardAccessors(prop, namedType, code);
|
2025-05-07 16:37:26 +08:00
|
|
|
|
}
|
2025-05-08 11:17:43 +08:00
|
|
|
|
|
|
|
|
|
|
if (propType is INamedTypeSymbol { IsTupleType: true } tupleType)
|
2025-04-28 14:07:51 +08:00
|
|
|
|
{
|
2025-05-08 11:17:43 +08:00
|
|
|
|
GenerateTupleAccessors(prop, tupleType, code);
|
2025-04-28 14:07:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-05-07 16:37:26 +08:00
|
|
|
|
|
|
|
|
|
|
//生成当前类属性名称集合
|
|
|
|
|
|
GeneratePropertyListForSourceEntity(propList, code, compilation, classSymbol);
|
2025-05-07 17:27:37 +08:00
|
|
|
|
|
|
|
|
|
|
//生成当前类属性信息集合
|
2025-05-08 11:17:43 +08:00
|
|
|
|
GenerateEntityMemberInfoList(propList, code, compilation, classSymbol);
|
2025-05-07 17:27:37 +08:00
|
|
|
|
|
2025-05-07 16:37:26 +08:00
|
|
|
|
|
|
|
|
|
|
//生成当前类属性访问
|
2025-05-08 11:17:43 +08:00
|
|
|
|
GetGeneratePropertyValueForSourceEntity(propList, code, compilation, classSymbol);
|
2025-05-07 16:37:26 +08:00
|
|
|
|
|
|
|
|
|
|
//生成当前类属性设置
|
2025-05-08 11:17:43 +08:00
|
|
|
|
SetGeneratePropertyValueForSourceEntity(propList, code, compilation, classSymbol);
|
|
|
|
|
|
|
2025-05-07 16:37:26 +08:00
|
|
|
|
code.AppendLine("}");
|
|
|
|
|
|
return code.ToString();
|
2025-04-28 14:07:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-05-08 14:42:13 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 生成ValueTuple元组属性访问器
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="prop"></param>
|
|
|
|
|
|
/// <param name="tupleType"></param>
|
|
|
|
|
|
/// <param name="code"></param>
|
2025-05-07 16:37:26 +08:00
|
|
|
|
private static void GenerateTupleAccessors(
|
2025-05-08 11:17:43 +08:00
|
|
|
|
IPropertySymbol prop,
|
|
|
|
|
|
INamedTypeSymbol tupleType,
|
|
|
|
|
|
StringBuilder code)
|
2025-04-28 14:07:51 +08:00
|
|
|
|
{
|
2025-05-08 11:17:43 +08:00
|
|
|
|
var parentType = prop.ContainingType.ToDisplayString();
|
2025-05-07 16:37:26 +08:00
|
|
|
|
var tupleElements = tupleType.TupleElements;
|
2025-04-28 14:07:51 +08:00
|
|
|
|
|
2025-05-07 16:37:26 +08:00
|
|
|
|
for (int i = 0; i < tupleElements.Length; i++)
|
2025-04-28 14:07:51 +08:00
|
|
|
|
{
|
2025-05-07 16:37:26 +08:00
|
|
|
|
var element = tupleElements[i];
|
2025-05-08 11:17:43 +08:00
|
|
|
|
var elementType = element.Type.ToDisplayString();
|
2025-05-07 16:37:26 +08:00
|
|
|
|
var elementName = element.Name;
|
|
|
|
|
|
|
2025-05-08 11:17:43 +08:00
|
|
|
|
// Getter
|
|
|
|
|
|
code.AppendLine($"public static {elementType} Get{prop.Name}_{elementName}({parentType} obj) => obj.{prop.Name}.{elementName};");
|
2025-05-07 16:37:26 +08:00
|
|
|
|
|
2025-05-08 11:17:43 +08:00
|
|
|
|
// Setter
|
2025-05-07 16:37:26 +08:00
|
|
|
|
if (prop.SetMethod != null)
|
|
|
|
|
|
{
|
2025-05-08 11:17:43 +08:00
|
|
|
|
code.AppendLine($"public static void Set{prop.Name}_{elementName}({parentType} obj, {elementType} value) => obj.{prop.Name} = ({string.Join(", ", GetTupleElements(prop.Name, tupleElements, i))});");
|
2025-05-07 16:37:26 +08:00
|
|
|
|
}
|
2025-04-28 14:07:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-05-08 11:17:43 +08:00
|
|
|
|
private static IEnumerable<string> GetTupleElements(
|
|
|
|
|
|
string propName,
|
|
|
|
|
|
ImmutableArray<IFieldSymbol> elements,
|
|
|
|
|
|
int targetIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (int i = 0; i < elements.Length; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
yield return i == targetIndex
|
|
|
|
|
|
? "value"
|
|
|
|
|
|
: $"obj.{propName}.{elements[i].Name}";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-05-08 17:21:20 +08:00
|
|
|
|
|
2025-05-06 23:46:12 +08:00
|
|
|
|
/// <summary>
|
2025-05-07 16:37:26 +08:00
|
|
|
|
/// 处理System.Tuple类型的访问器生成
|
2025-05-06 23:46:12 +08:00
|
|
|
|
/// </summary>
|
2025-05-07 16:37:26 +08:00
|
|
|
|
private static void GenerateSystemTupleAccessors(
|
|
|
|
|
|
IPropertySymbol prop,
|
|
|
|
|
|
INamedTypeSymbol tupleType,
|
|
|
|
|
|
StringBuilder code,
|
|
|
|
|
|
INamedTypeSymbol classSymbol)
|
2025-04-28 14:07:51 +08:00
|
|
|
|
{
|
2025-05-07 16:37:26 +08:00
|
|
|
|
var parentType = classSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
|
|
|
|
|
var elementTypes = tupleType.TypeArguments;
|
|
|
|
|
|
var tupleTypeName = tupleType.ToDisplayString();
|
2025-04-28 14:07:51 +08:00
|
|
|
|
|
2025-05-07 16:37:26 +08:00
|
|
|
|
for (int i = 0; i < elementTypes.Length; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
var elementType = elementTypes[i].ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
|
|
|
|
|
var elementName = $"Item{i + 1}";
|
2025-04-28 14:07:51 +08:00
|
|
|
|
|
2025-05-07 16:37:26 +08:00
|
|
|
|
// Getter
|
|
|
|
|
|
code.AppendLine(
|
|
|
|
|
|
$" public static {elementType} Get{prop.Name}_{elementName}" +
|
|
|
|
|
|
$"({parentType} obj) => obj.{prop.Name}.{elementName};");
|
|
|
|
|
|
|
|
|
|
|
|
// Setter
|
|
|
|
|
|
if (prop.SetMethod != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var assignments = elementTypes.Select((_, idx) =>
|
|
|
|
|
|
idx == i ? "value" : $"obj.{prop.Name}.Item{idx + 1}"
|
|
|
|
|
|
).ToList();
|
|
|
|
|
|
|
|
|
|
|
|
code.AppendLine(
|
|
|
|
|
|
$" public static void Set{prop.Name}_{elementName}" +
|
|
|
|
|
|
$"({parentType} obj, {elementType} value) => " +
|
|
|
|
|
|
$"obj.{prop.Name} = new {tupleTypeName}({string.Join(", ", assignments)});");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-04-28 14:07:51 +08:00
|
|
|
|
}
|
2025-05-08 17:21:20 +08:00
|
|
|
|
|
2025-05-06 23:46:12 +08:00
|
|
|
|
/// <summary>
|
2025-05-07 16:37:26 +08:00
|
|
|
|
/// 增强的工厂类实现
|
2025-05-06 23:46:12 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
private static string BuildFactoryCode()
|
|
|
|
|
|
{
|
|
|
|
|
|
return """
|
2025-05-07 16:37:26 +08:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Concurrent;
|
|
|
|
|
|
using System.Reflection;
|
|
|
|
|
|
|
|
|
|
|
|
namespace JiShe.CollectBus.Analyzers.Shared;
|
|
|
|
|
|
|
|
|
|
|
|
public static class SourceEntityAccessorFactory
|
|
|
|
|
|
{
|
|
|
|
|
|
private static readonly ConcurrentDictionary<Type, object> _accessors = new();
|
2025-05-07 17:20:10 +08:00
|
|
|
|
|
2025-05-07 16:37:26 +08:00
|
|
|
|
public static ISourceEntityAccessor<T> GetAccessor<T>()
|
2025-05-06 23:46:12 +08:00
|
|
|
|
{
|
2025-05-07 16:37:26 +08:00
|
|
|
|
return (ISourceEntityAccessor<T>)_accessors.GetOrAdd(typeof(T), t =>
|
2025-05-06 23:46:12 +08:00
|
|
|
|
{
|
2025-05-07 17:20:10 +08:00
|
|
|
|
// 获取泛型类型定义信息(如果是泛型类型)
|
|
|
|
|
|
var isGeneric = t.IsGenericType;
|
|
|
|
|
|
var genericTypeDef = isGeneric ? t.GetGenericTypeDefinition() : null;
|
|
|
|
|
|
var arity = isGeneric ? genericTypeDef!.GetGenericArguments().Length : 0;
|
|
|
|
|
|
|
|
|
|
|
|
// 构建访问器类名
|
|
|
|
|
|
var typeName = isGeneric
|
|
|
|
|
|
? $"{t.Namespace}.{genericTypeDef!.Name.Split('`')[0]}Accessor`{arity}"
|
|
|
|
|
|
: $"{t.Namespace}.{t.Name}Accessor";
|
|
|
|
|
|
|
|
|
|
|
|
// 尝试从当前程序集加载
|
|
|
|
|
|
var accessorType = Assembly.GetAssembly(t)!.GetType(typeName)
|
|
|
|
|
|
?? throw new InvalidOperationException($"Accessor type {typeName} not found");
|
|
|
|
|
|
|
|
|
|
|
|
// 处理泛型参数
|
|
|
|
|
|
if (isGeneric && accessorType.IsGenericTypeDefinition)
|
2025-05-06 23:46:12 +08:00
|
|
|
|
{
|
2025-05-07 17:20:10 +08:00
|
|
|
|
accessorType = accessorType.MakeGenericType(t.GetGenericArguments());
|
2025-05-06 23:46:12 +08:00
|
|
|
|
}
|
2025-05-07 17:20:10 +08:00
|
|
|
|
|
|
|
|
|
|
return Activator.CreateInstance(accessorType)!;
|
2025-05-07 16:37:26 +08:00
|
|
|
|
});
|
2025-05-06 23:46:12 +08:00
|
|
|
|
}
|
2025-05-07 16:37:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
""";
|
2025-05-06 23:46:12 +08:00
|
|
|
|
}
|
2025-05-07 10:15:45 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-05-07 16:37:26 +08:00
|
|
|
|
/// 属性访问生成逻辑
|
2025-05-07 10:15:45 +08:00
|
|
|
|
/// </summary>
|
2025-05-07 16:37:26 +08:00
|
|
|
|
/// <param name="propList">属性集合</param>
|
|
|
|
|
|
/// <param name="code"></param>
|
2025-05-07 10:15:45 +08:00
|
|
|
|
/// <param name="compilation"></param>
|
2025-05-07 16:37:26 +08:00
|
|
|
|
/// <param name="classSymbol"></param>
|
|
|
|
|
|
private static void GetGeneratePropertyValueForSourceEntity(
|
|
|
|
|
|
IEnumerable<IPropertySymbol> propList,
|
2025-05-07 10:15:45 +08:00
|
|
|
|
StringBuilder code,
|
|
|
|
|
|
Compilation compilation,
|
|
|
|
|
|
INamedTypeSymbol classSymbol)
|
|
|
|
|
|
{
|
2025-05-07 16:37:26 +08:00
|
|
|
|
code.AppendLine($" public object GetPropertyValue({classSymbol} targetEntity, string propertyName)");
|
|
|
|
|
|
code.AppendLine(" {");
|
|
|
|
|
|
code.AppendLine(" return propertyName switch");
|
2025-05-07 10:15:45 +08:00
|
|
|
|
code.AppendLine(" {");
|
|
|
|
|
|
|
2025-05-07 16:37:26 +08:00
|
|
|
|
foreach (var prop in propList)
|
|
|
|
|
|
{
|
2025-05-08 11:17:43 +08:00
|
|
|
|
code.AppendLine(
|
|
|
|
|
|
$" \"{prop.Name}\" => " +
|
|
|
|
|
|
$"Get{prop.Name}(targetEntity),");
|
|
|
|
|
|
|
2025-05-07 16:37:26 +08:00
|
|
|
|
if (prop.Type is INamedTypeSymbol { IsTupleType: true } tupleType)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var element in tupleType.TupleElements)
|
|
|
|
|
|
{
|
|
|
|
|
|
code.AppendLine(
|
|
|
|
|
|
$" \"{prop.Name}.{element.Name}\" => " +
|
|
|
|
|
|
$"Get{prop.Name}_{element.Name}(targetEntity),");
|
|
|
|
|
|
}
|
2025-05-07 10:15:45 +08:00
|
|
|
|
}
|
2025-05-08 17:21:20 +08:00
|
|
|
|
|
2025-05-07 10:15:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-05-07 16:37:26 +08:00
|
|
|
|
code.AppendLine(" _ => throw new ArgumentException($\"Unknown property: {propertyName}\")");
|
|
|
|
|
|
code.AppendLine(" };");
|
|
|
|
|
|
code.AppendLine(" }");
|
2025-05-07 10:15:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-05-07 16:37:26 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 属性设置生成逻辑
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="propList">属性集合</param>
|
|
|
|
|
|
/// <param name="code"></param>
|
|
|
|
|
|
/// <param name="compilation"></param>
|
|
|
|
|
|
/// <param name="classSymbol"></param>
|
|
|
|
|
|
private static void SetGeneratePropertyValueForSourceEntity(
|
|
|
|
|
|
IEnumerable<IPropertySymbol> propList,
|
|
|
|
|
|
StringBuilder code,
|
|
|
|
|
|
Compilation compilation,
|
|
|
|
|
|
INamedTypeSymbol classSymbol)
|
2025-05-07 10:15:45 +08:00
|
|
|
|
{
|
2025-05-07 16:37:26 +08:00
|
|
|
|
code.AppendLine($" public void SetPropertyValue({classSymbol} targetEntity, string propertyName, object value)");
|
|
|
|
|
|
code.AppendLine(" {");
|
|
|
|
|
|
code.AppendLine(" switch (propertyName)");
|
2025-05-07 10:15:45 +08:00
|
|
|
|
code.AppendLine(" {");
|
|
|
|
|
|
|
2025-05-07 16:37:26 +08:00
|
|
|
|
foreach (var prop in propList)
|
2025-05-07 10:15:45 +08:00
|
|
|
|
{
|
2025-05-08 11:17:43 +08:00
|
|
|
|
var propType = prop.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
|
|
|
|
|
code.AppendLine($" case \"{prop.Name}\":");
|
|
|
|
|
|
code.AppendLine($" Set{prop.Name}(");
|
|
|
|
|
|
code.AppendLine($" targetEntity, ({propType})value);");
|
|
|
|
|
|
code.AppendLine(" break;");
|
|
|
|
|
|
|
2025-05-07 16:37:26 +08:00
|
|
|
|
if (prop.Type is INamedTypeSymbol { IsTupleType: true } tupleType)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var element in tupleType.TupleElements)
|
|
|
|
|
|
{
|
|
|
|
|
|
var elementType = element.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
|
|
|
|
|
code.AppendLine($" case \"{prop.Name}.{element.Name}\":");
|
|
|
|
|
|
code.AppendLine($" Set{prop.Name}_{element.Name}(");
|
|
|
|
|
|
code.AppendLine($" targetEntity, ({elementType})value);");
|
|
|
|
|
|
code.AppendLine(" break;");
|
|
|
|
|
|
}
|
2025-05-08 17:21:20 +08:00
|
|
|
|
}
|
2025-05-07 10:15:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-05-07 16:37:26 +08:00
|
|
|
|
code.AppendLine(" default:");
|
|
|
|
|
|
code.AppendLine(" throw new ArgumentException($\"Unknown property: {propertyName}\");");
|
|
|
|
|
|
code.AppendLine(" }");
|
|
|
|
|
|
code.AppendLine(" }");
|
2025-05-07 10:15:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-05-07 16:37:26 +08:00
|
|
|
|
/// 属性名称集合
|
2025-05-07 10:15:45 +08:00
|
|
|
|
/// </summary>
|
2025-05-07 16:37:26 +08:00
|
|
|
|
/// <param name="propList">属性集合</param>
|
2025-05-07 10:15:45 +08:00
|
|
|
|
/// <param name="code"></param>
|
2025-05-07 16:37:26 +08:00
|
|
|
|
/// <param name="compilation"></param>
|
|
|
|
|
|
/// <param name="classSymbol"></param>
|
|
|
|
|
|
private static void GeneratePropertyListForSourceEntity(
|
|
|
|
|
|
IEnumerable<IPropertySymbol> propList,
|
|
|
|
|
|
StringBuilder code,
|
|
|
|
|
|
Compilation compilation,
|
|
|
|
|
|
INamedTypeSymbol classSymbol)
|
2025-05-07 10:15:45 +08:00
|
|
|
|
{
|
2025-05-08 08:43:37 +08:00
|
|
|
|
code.AppendLine(" public List<string> PropertyNameList {get;} = new List<string>()");
|
2025-05-07 16:37:26 +08:00
|
|
|
|
code.AppendLine(" {");
|
|
|
|
|
|
List<string> tempPropList = new List<string>();
|
|
|
|
|
|
foreach (var prop in propList)
|
2025-05-07 10:15:45 +08:00
|
|
|
|
{
|
2025-05-07 16:37:26 +08:00
|
|
|
|
if (prop.Type is INamedTypeSymbol { IsTupleType: true } tupleType)
|
2025-05-08 11:17:43 +08:00
|
|
|
|
{
|
2025-05-07 16:37:26 +08:00
|
|
|
|
foreach (var element in tupleType.TupleElements)
|
|
|
|
|
|
{
|
|
|
|
|
|
tempPropList.Add($"\"{prop.Name}.{element.Name}\"");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
2025-05-07 10:15:45 +08:00
|
|
|
|
{
|
2025-05-07 16:37:26 +08:00
|
|
|
|
tempPropList.Add($"\"{prop.Name}\"");
|
2025-05-07 10:15:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-05-07 16:37:26 +08:00
|
|
|
|
code.Append(string.Join(",", tempPropList));
|
2025-05-07 10:15:45 +08:00
|
|
|
|
|
2025-05-07 16:37:26 +08:00
|
|
|
|
code.AppendLine(" };");
|
2025-05-07 10:15:45 +08:00
|
|
|
|
}
|
2025-05-07 17:27:37 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-05-08 11:17:43 +08:00
|
|
|
|
/// 生成当前类属性信息集合
|
2025-05-07 17:27:37 +08:00
|
|
|
|
/// </summary>
|
2025-05-08 11:17:43 +08:00
|
|
|
|
private static void GenerateEntityMemberInfoList(
|
2025-05-08 17:21:20 +08:00
|
|
|
|
IEnumerable<IPropertySymbol> propList,
|
|
|
|
|
|
StringBuilder code,
|
|
|
|
|
|
Compilation compilation,
|
|
|
|
|
|
INamedTypeSymbol classSymbol)
|
2025-05-07 17:27:37 +08:00
|
|
|
|
{
|
2025-05-08 14:42:13 +08:00
|
|
|
|
code.AppendLine(" public List<EntityMemberInfo> MemberList { get; } = new()");
|
2025-05-07 17:27:37 +08:00
|
|
|
|
code.AppendLine(" {");
|
2025-05-08 08:43:37 +08:00
|
|
|
|
|
|
|
|
|
|
var initializerLines = new List<string>();
|
2025-05-08 10:28:23 +08:00
|
|
|
|
|
2025-05-07 17:27:37 +08:00
|
|
|
|
foreach (var prop in propList)
|
|
|
|
|
|
{
|
2025-05-08 17:21:20 +08:00
|
|
|
|
var entityType = prop.ContainingType.ToDisplayString();//entity 实体类型名称
|
|
|
|
|
|
var propType = prop.Type;//实体属性的类型
|
|
|
|
|
|
var propTypeName = propType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
2025-05-12 17:08:09 +08:00
|
|
|
|
// var declaredTypeName = propType.Name; // 直接获取类型名称(如 "Int32")
|
|
|
|
|
|
// 处理可空类型,获取底层具体类型名称
|
|
|
|
|
|
var declaredTypeName = propType switch
|
|
|
|
|
|
{
|
|
|
|
|
|
INamedTypeSymbol { OriginalDefinition.SpecialType: SpecialType.System_Nullable_T } nullableType =>
|
|
|
|
|
|
nullableType.TypeArguments[0].Name, // 提取如 "Int32"
|
|
|
|
|
|
_ => propType.Name
|
|
|
|
|
|
};
|
2025-05-08 14:42:13 +08:00
|
|
|
|
|
|
|
|
|
|
// 处理主属性
|
|
|
|
|
|
var propAttributes = prop.GetAttributes()
|
|
|
|
|
|
.Where(a => !IsCompilerGeneratedAttribute(a))
|
|
|
|
|
|
.ToList();
|
|
|
|
|
|
|
|
|
|
|
|
var attributeInitializers = propAttributes
|
|
|
|
|
|
.Select(GenerateAttributeInitializer)
|
|
|
|
|
|
.Where(s => !string.IsNullOrEmpty(s));
|
|
|
|
|
|
|
|
|
|
|
|
var mainMember = new StringBuilder();
|
|
|
|
|
|
mainMember.Append(
|
2025-05-08 11:17:43 +08:00
|
|
|
|
$"new EntityMemberInfo(" +
|
|
|
|
|
|
$"\"{prop.Name}\", " +
|
2025-05-08 17:21:20 +08:00
|
|
|
|
$"typeof({propTypeName}), " +
|
|
|
|
|
|
$"\"{declaredTypeName}\", " +
|
|
|
|
|
|
$"(e) => Get{prop.Name}(({entityType})e), " +
|
|
|
|
|
|
$"(e, v) => Set{prop.Name}(({entityType})e, ({propTypeName})v))");
|
2025-05-08 11:17:43 +08:00
|
|
|
|
|
2025-05-08 14:42:13 +08:00
|
|
|
|
if (attributeInitializers.Any())
|
|
|
|
|
|
{
|
|
|
|
|
|
mainMember.AppendLine();
|
|
|
|
|
|
mainMember.Append(" { CustomAttributes = new List<Attribute>");
|
|
|
|
|
|
mainMember.Append($" {{ {string.Join(", ", attributeInitializers)} }} }}");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
initializerLines.Add(mainMember.ToString());
|
|
|
|
|
|
|
2025-05-08 17:21:20 +08:00
|
|
|
|
// 处理元组元素,(暂不需要处理元组元素的特性)
|
2025-05-07 17:27:37 +08:00
|
|
|
|
if (prop.Type is INamedTypeSymbol { IsTupleType: true } tupleType)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var element in tupleType.TupleElements)
|
|
|
|
|
|
{
|
2025-05-08 17:21:20 +08:00
|
|
|
|
var elementType = element.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);//元组元素的类型
|
|
|
|
|
|
var elementName = element.Name;//元组元素名称
|
|
|
|
|
|
var elementDeclaredName = element.Type.Name;//元组元素类型名称
|
2025-05-08 11:17:43 +08:00
|
|
|
|
|
2025-05-08 08:43:37 +08:00
|
|
|
|
initializerLines.Add(
|
2025-05-08 17:21:20 +08:00
|
|
|
|
$"new EntityMemberInfo(" +
|
|
|
|
|
|
$"\"{prop.Name}.{elementName}\", " +
|
|
|
|
|
|
$"typeof({elementType}), " +
|
2025-05-09 17:54:52 +08:00
|
|
|
|
$"typeof({elementType}).Name, " +//$"\"{elementDeclaredName}\", " +
|
2025-05-08 17:21:20 +08:00
|
|
|
|
$"(e) => Get{prop.Name}_{elementName}(({entityType})e), " +
|
|
|
|
|
|
$"(e, v) => Set{prop.Name}_{elementName}(({entityType})e, ({elementType})v))");
|
2025-05-07 17:27:37 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-05-08 08:43:37 +08:00
|
|
|
|
code.AppendLine(string.Join(",\n", initializerLines));
|
2025-05-07 17:27:37 +08:00
|
|
|
|
code.AppendLine(" };");
|
2025-05-08 14:42:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static string GenerateAttributeInitializer(AttributeData attribute)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (attribute.AttributeClass == null)
|
|
|
|
|
|
return string.Empty;
|
|
|
|
|
|
|
|
|
|
|
|
var attributeClass = attribute.AttributeClass.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
|
|
|
|
|
var args = attribute.ConstructorArguments;
|
|
|
|
|
|
var namedArgs = attribute.NamedArguments;
|
|
|
|
|
|
|
|
|
|
|
|
var parameters = new List<string>();
|
|
|
|
|
|
foreach (var arg in args)
|
|
|
|
|
|
{
|
|
|
|
|
|
parameters.Add(ConvertTypedConstantToCode(arg));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var constructorArgs = string.Join(", ", parameters);
|
|
|
|
|
|
|
|
|
|
|
|
var initializer = new StringBuilder();
|
|
|
|
|
|
initializer.Append($"new {attributeClass}({constructorArgs})");
|
|
|
|
|
|
|
|
|
|
|
|
if (namedArgs.Any())
|
|
|
|
|
|
{
|
|
|
|
|
|
initializer.Append(" { ");
|
|
|
|
|
|
var namedArgsList = namedArgs.Select(n => $"{n.Key} = {ConvertTypedConstantToCode(n.Value)}");
|
|
|
|
|
|
initializer.Append(string.Join(", ", namedArgsList));
|
|
|
|
|
|
initializer.Append(" }");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return initializer.ToString();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static string ConvertTypedConstantToCode(TypedConstant constant)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (constant.IsNull)
|
|
|
|
|
|
return "null";
|
|
|
|
|
|
|
|
|
|
|
|
switch (constant.Kind)
|
|
|
|
|
|
{
|
|
|
|
|
|
case TypedConstantKind.Array:
|
|
|
|
|
|
var elements = constant.Values.Select(ConvertTypedConstantToCode);
|
|
|
|
|
|
return $"new[] {{ {string.Join(", ", elements)} }}";
|
|
|
|
|
|
case TypedConstantKind.Type:
|
|
|
|
|
|
var typeSymbol = (ITypeSymbol)constant.Value!;
|
|
|
|
|
|
return $"typeof({typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)})";
|
|
|
|
|
|
case TypedConstantKind.Enum:
|
|
|
|
|
|
return ConvertEnumTypedConstant(constant);
|
|
|
|
|
|
default:
|
|
|
|
|
|
return ConvertPrimitiveConstant(constant);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static string ConvertEnumTypedConstant(TypedConstant constant)
|
|
|
|
|
|
{
|
|
|
|
|
|
var enumType = constant.Type!;
|
|
|
|
|
|
var enumValue = constant.Value!;
|
|
|
|
|
|
var enumTypeName = enumType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var member in enumType.GetMembers().OfType<IFieldSymbol>())
|
|
|
|
|
|
{
|
|
|
|
|
|
if (member.ConstantValue != null && member.ConstantValue.Equals(enumValue))
|
|
|
|
|
|
return $"{enumTypeName}.{member.Name}";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return $"({enumTypeName})({enumValue})";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static string ConvertPrimitiveConstant(TypedConstant constant)
|
|
|
|
|
|
{
|
|
|
|
|
|
var value = constant.Value!;
|
|
|
|
|
|
return value switch
|
|
|
|
|
|
{
|
|
|
|
|
|
string s => $"\"{s}\"",
|
|
|
|
|
|
char c => $"'{c}'",
|
|
|
|
|
|
bool b => b ? "true" : "false",
|
|
|
|
|
|
_ => value.ToString()
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static bool IsCompilerGeneratedAttribute(AttributeData attribute)
|
|
|
|
|
|
{
|
|
|
|
|
|
return attribute.AttributeClass?.ToDisplayString() == "System.Runtime.CompilerServices.CompilerGeneratedAttribute";
|
|
|
|
|
|
}
|
2025-05-08 17:21:20 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取枚举的参数
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="enumType"></param>
|
|
|
|
|
|
/// <param name="value"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
private static string GetEnumMemberName(INamedTypeSymbol enumType, int value)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var member in enumType.GetMembers().OfType<IFieldSymbol>())
|
|
|
|
|
|
{
|
|
|
|
|
|
if (member.ConstantValue is int intValue && intValue == value)
|
|
|
|
|
|
{
|
|
|
|
|
|
return $"{enumType.ToDisplayString()}.{member.Name}";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return $"{enumType.ToDisplayString()}.Other";
|
|
|
|
|
|
}
|
2025-04-28 14:07:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|