using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; namespace JiShe.CollectBus.IncrementalGenerator { /// /// 复杂类型增量源生成器 /// [Generator(LanguageNames.CSharp)] public class ComplexTypeSourceAnalyzers : IIncrementalGenerator { private const string AttributeFullName = "JiShe.CollectBus.Analyzers.Shared.SourceAnalyzersAttribute"; private const string SourceEntityAccessorFactoryNamespace = "JiShe.CollectBus.Analyzers.Shared"; public void Initialize(IncrementalGeneratorInitializationContext context) { //Debugger.Launch(); // 步骤1:筛选带有 [SourceAnalyzers] 的类 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) => GenerateCode(source.Left, source.Right!, spc)); } private static bool IsClassWithAttribute(SyntaxNode node) => node is ClassDeclarationSyntax cds && cds.AttributeLists.Count > 0; private static ClassDeclarationSyntax GetClassDeclaration(GeneratorSyntaxContext context) { 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; } /// /// 递归获取所有层级的属性 /// /// /// private static IEnumerable GetAllPropertiesInHierarchy(INamedTypeSymbol classSymbol) { var currentSymbol = classSymbol; while (currentSymbol != null) { foreach (var prop in currentSymbol.GetMembers().OfType()) { yield return prop; } currentSymbol = currentSymbol.BaseType; // 向上遍历基类 } } /// /// 生成代码 /// /// /// /// private static void GenerateCode( Compilation compilation, IEnumerable classes, SourceProductionContext context) { var processedTypes = new HashSet(SymbolEqualityComparer.Default); if (!classes.Any()) { context.ReportDiagnostic(Diagnostic.Create( new DiagnosticDescriptor("GEN002", "没有目标类", "没有找到SourceAnalyzers标记的类", "Debug", DiagnosticSeverity.Warning, true), Location.None)); } foreach (var classDecl in classes.Distinct()) { var model = compilation.GetSemanticModel(classDecl.SyntaxTree); var classSymbol = model.GetDeclaredSymbol(classDecl) as INamedTypeSymbol; if (classSymbol == null || !processedTypes.Add(classSymbol)) { context.ReportDiagnostic(Diagnostic.Create( new DiagnosticDescriptor("GEN003", "无效符号", $"类名称为{classDecl.Identifier.Text} 符号为空", "Error", DiagnosticSeverity.Error, true), Location.None)); continue; } var code = BuildAccessorsForType(classSymbol, compilation, processedTypes); context.AddSource($"{classSymbol.Name}Extension.g.cs", code); var code3 = BuildAccessorsForSourceEntity(classSymbol, compilation, processedTypes); context.AddSource($"{classSymbol.Name}Accessor.g.cs", code3); } // 生成工厂注册代码 context.AddSource("SourceEntityAccessorFactory.g.cs", BuildFactoryCode()); } /// /// 构建类的属性访问器代码 /// /// /// /// /// private static string BuildAccessorsForType( INamedTypeSymbol classSymbol, Compilation compilation, HashSet processedTypes) { var code = new StringBuilder(); code.AppendLine("#pragma warning disable CS0419 // 禁用警告"); code.AppendLine("// Generated code for " + classSymbol.Name); code.AppendLine("// "); code.AppendLine("#nullable enable"); code.AppendLine($"namespace {classSymbol.ContainingNamespace.ToDisplayString()};"); code.AppendLine(); code.AppendLine($"public static class {classSymbol.Name}Extension{GetGenericParams(classSymbol)}"); code.AppendLine("{"); foreach (var prop in GetAllPropertiesInHierarchy(classSymbol)) { if (prop.IsIndexer) continue; GeneratePropertyAccessorsForType(prop, code, compilation, processedTypes); } code.AppendLine("}"); return code.ToString(); } /// /// 获取泛型参数 /// /// /// public static string GetGenericParams(INamedTypeSymbol symbol) { if (!symbol.IsGenericType) return ""; var parameters = symbol.TypeParameters.Select(t => t.Name); return $"<{string.Join(", ", parameters)}>"; } /// /// 生成属性访问器代码 /// /// /// /// /// private static void GeneratePropertyAccessorsForType( IPropertySymbol prop, StringBuilder code, Compilation compilation, HashSet processedTypes) { // 安全类型转换 if (prop.Type is not ITypeSymbol propType) return; code.AppendLine($" // Processing property: {prop.Name}"); // 处理元组类型 if (propType is INamedTypeSymbol { IsTupleType: true } tupleType) { GenerateTupleAccessorsForType(prop, tupleType, code); } else if (propType is INamedTypeSymbol namedType) { GenerateStandardAccessorsForType(prop, namedType, code); ProcessNestedType(namedType, compilation, processedTypes); } } /// /// 处理元组类型 /// /// /// /// private static void GenerateTupleAccessorsForType(IPropertySymbol prop, INamedTypeSymbol tupleType, StringBuilder code) { var elements = tupleType.TupleElements; var parentType = prop.ContainingType.ToDisplayString(); for (int i = 0; i < elements.Length; i++) { var element = elements[i]; if (element.Type is not ITypeSymbol elementType) continue; var elementName = element.CorrespondingTupleField?.Name ?? $"Item{i + 1}"; code.AppendLine($" public static {elementType.ToDisplayString()} Get{prop.Name}_{elementName}({parentType} obj) => obj.{prop.Name}.{elementName};"); if (prop.SetMethod != null) { var assignments = elements.Select((e, idx) => idx == i ? "value" : $"obj.{prop.Name}.{e.Name}"); code.AppendLine($" public static void Set{prop.Name}_{elementName}({parentType} obj, {elementType.ToDisplayString()} value) => obj.{prop.Name} = ({string.Join(", ", assignments)});"); } } } /// /// 生成标准属性的访问器 /// /// /// /// private static void GenerateStandardAccessorsForType(IPropertySymbol prop, INamedTypeSymbol propType, StringBuilder code) { var parentType = prop.ContainingType.ToDisplayString(); code.AppendLine($" public static {propType.ToDisplayString()} Get{prop.Name}({parentType} obj) => obj.{prop.Name};"); if (prop.SetMethod != null) { code.AppendLine($" public static void Set{prop.Name}({parentType} obj, {propType.ToDisplayString()} value) => obj.{prop.Name} = value;"); } } /// /// 处理嵌套类型 /// /// /// /// private static void ProcessNestedType(ITypeSymbol typeSymbol, Compilation compilation, HashSet processedTypes) { if (typeSymbol is not INamedTypeSymbol namedType) return; if (!ShouldProcessNestedType(namedType)) return; if (!processedTypes.Add(namedType)) return; var code = BuildAccessorsForType(namedType, compilation, processedTypes); } /// /// 处理嵌套类型 /// /// /// private static bool ShouldProcessNestedType(INamedTypeSymbol symbol) { return symbol.DeclaredAccessibility == Accessibility.Public && !symbol.IsTupleType && !symbol.IsAnonymousType && !symbol.IsImplicitlyDeclared && !symbol.Name.StartsWith("<"); } /// /// 生成扩展类工厂代码 /// /// private static string BuildFactoryCode() { return """ using System; using System.Collections.Concurrent; namespace JiShe.CollectBus.Analyzers.Shared; public static class SourceEntityAccessorFactory { private static readonly ConcurrentDictionary _accessors = new(); public static ISourceEntityAccessor GetAccessor() { if (!_accessors.TryGetValue(typeof(T), out var accessor)) { accessor = Activator.CreateInstance( Type.GetType($"{typeof(T).Namespace}.{typeof(T).Name}Accessor")!)!; _accessors.TryAdd(typeof(T), accessor); } return (ISourceEntityAccessor)accessor!; } } """; } /// /// 构建实体类的源属性访问器代码 /// /// /// /// /// private static string BuildAccessorsForSourceEntity( INamedTypeSymbol classSymbol, Compilation compilation, HashSet processedTypes) { var code = new StringBuilder(); code.AppendLine("#pragma warning disable CS0419 // 禁用警告"); code.AppendLine("// Generated code for " + classSymbol.Name); code.AppendLine("// "); code.AppendLine("#nullable enable"); code.AppendLine("using System;"); code.AppendLine("using JiShe.CollectBus.Analyzers.Shared;"); code.AppendLine($"namespace {classSymbol.ContainingNamespace.ToDisplayString()};"); code.AppendLine(); code.AppendLine($"public sealed class {classSymbol.Name}Accessor : ISourceEntityAccessor<{classSymbol.Name}>"); code.AppendLine("{"); GetGeneratePropertyValueForSourceEntity(GetAllPropertiesInHierarchy(classSymbol), code, compilation, classSymbol); SetGeneratePropertyValueForSourceEntity(GetAllPropertiesInHierarchy(classSymbol), code, compilation, classSymbol); code.AppendLine("}"); return code.ToString(); } private static void GetGeneratePropertyValueForSourceEntity(IEnumerable propList, StringBuilder code, Compilation compilation, INamedTypeSymbol classSymbol) { code.AppendLine($" public object GetPropertyValue({classSymbol.Name} targetEntity, string propertyName)"); code.AppendLine(" {"); code.AppendLine(" return propertyName switch"); code.AppendLine(" {"); // 遍历所有属性 foreach (var property in propList) { // 安全类型转换 if (property.Type is not ITypeSymbol propType) continue; // 处理元组类型 if (propType is INamedTypeSymbol { IsTupleType: true } tupleType) { } else if (propType is INamedTypeSymbol namedType) { // 生成属性访问的 code.AppendLine($" \"{property.Name}\" => {classSymbol.Name}Extension.Get{property.Name}(targetEntity),"); } } code.AppendLine(" _ => throw new ArgumentException($\"Unknown property: {propertyName}\")"); code.AppendLine(" };"); code.AppendLine(" }"); } private static void SetGeneratePropertyValueForSourceEntity(IEnumerable propList, StringBuilder code, Compilation compilation, INamedTypeSymbol classSymbol) { code.AppendLine($" public void SetPropertyValue({classSymbol.Name} targetEntity, string propertyName, object value)"); code.AppendLine(" {"); code.AppendLine(" return propertyName switch"); code.AppendLine(" {"); // 遍历所有属性 foreach (var property in propList) { // 安全类型转换 if (property.Type is not ITypeSymbol propType) continue; // 处理元组类型 if (propType is INamedTypeSymbol { IsTupleType: true } tupleType) { } else if (propType is INamedTypeSymbol namedType) { // 生成属性设置赋值 code.AppendLine($" \"{property.Name}\" => {classSymbol.Name}Extension.Set{property.Name}(targetEntity,({namedType.ToDisplayString()})value),"); } } code.AppendLine(" _ => throw new ArgumentException($\"Unknown property: {propertyName}\")"); code.AppendLine(" };"); code.AppendLine(" }"); } /// /// 处理元组类型 /// /// /// /// private static void GenerateTupleAccessorsForSourceEntity(IPropertySymbol prop, INamedTypeSymbol tupleType, StringBuilder code) { var elements = tupleType.TupleElements; var parentType = prop.ContainingType.ToDisplayString(); for (int i = 0; i < elements.Length; i++) { var element = elements[i]; if (element.Type is not ITypeSymbol elementType) continue; var elementName = element.CorrespondingTupleField?.Name ?? $"Item{i + 1}"; code.AppendLine($" public static {elementType.ToDisplayString()} Get{prop.Name}_{elementName}({parentType} obj) => obj.{prop.Name}.{elementName};"); if (prop.SetMethod != null) { var assignments = elements.Select((e, idx) => idx == i ? "value" : $"obj.{prop.Name}.{e.Name}"); code.AppendLine($" public static void Set{prop.Name}_{elementName}({parentType} obj, {elementType.ToDisplayString()} value) => obj.{prop.Name} = ({string.Join(", ", assignments)});"); } } } /// /// 生成标准属性的访问器 /// /// /// /// private static void GenerateStandardAccessorsForSourceEntity(IPropertySymbol prop, INamedTypeSymbol propType, StringBuilder code) { var parentType = prop.ContainingType.ToDisplayString(); code.AppendLine($" public object {propType.ToDisplayString()} Get{prop.Name}({parentType} obj) => obj.{prop.Name};"); if (prop.SetMethod != null) { code.AppendLine($" public static void Set{prop.Name}({parentType} obj, {propType.ToDisplayString()} value) => obj.{prop.Name} = value;"); } } } }