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";
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 code3 = BuildAccessorsForSourceEntity(classSymbol, compilation, processedTypes);
context.AddSource($"{classSymbol.Name}Accessor.g.cs", code3);
}
// 生成工厂注册代码
context.AddSource("SourceEntityAccessorFactory.g.cs", BuildFactoryCode());
}
///
/// 获取泛型参数
///
///
///
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 GenerateStandardAccessors(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 string BuildAccessorsForSourceEntity(
INamedTypeSymbol classSymbol,
Compilation compilation,
HashSet processedTypes)
{
var code = new StringBuilder();
code.AppendLine("// ");
code.AppendLine("#nullable enable");
code.AppendLine("using System;");
code.AppendLine("using System.Reflection;");
code.AppendLine("using System.Collections.Generic;");
code.AppendLine("using JiShe.CollectBus.Analyzers.Shared;");
code.AppendLine($"namespace {classSymbol.ContainingNamespace.ToDisplayString()};");
code.AppendLine();
// 处理泛型类型名称
var accessibility = classSymbol.DeclaredAccessibility switch
{
Accessibility.Public => "public",
_ => "internal"
};
var genericParams = classSymbol.IsGenericType
? $"<{string.Join(", ", classSymbol.TypeParameters.Select(t => t.Name))}>"
: "";
code.AppendLine(
$"{accessibility} sealed class {classSymbol.Name}Accessor{genericParams} " + // 保留泛型参数
$": ISourceEntityAccessor<{classSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}>");
code.AppendLine("{");
var propList = GetAllPropertiesInHierarchy(classSymbol);
foreach (var prop in propList)
{
// 安全类型转换
if (prop.Type is not ITypeSymbol propType) continue;
if (propType is INamedTypeSymbol { IsTupleType: true } tupleType)
{
GenerateTupleAccessors(prop, tupleType, code, classSymbol);
}
else if (propType is INamedTypeSymbol namedType)
{
GenerateStandardAccessors(prop, namedType, code);
}
}
//生成当前类属性名称集合
GeneratePropertyListForSourceEntity(propList, code, compilation, classSymbol);
//生成当前类属性信息集合
GeneratePropertyInfoListForSourceEntity(
propList,
code,
compilation,
classSymbol);
//生成当前类属性访问
GetGeneratePropertyValueForSourceEntity(
propList,
code,
compilation,
classSymbol);
//生成当前类属性设置
SetGeneratePropertyValueForSourceEntity(
propList,
code,
compilation,
classSymbol);
code.AppendLine("}");
return code.ToString();
}
///
/// 生成泛型ValueTuple 元组访问器
///
private static void GenerateTupleAccessors(
IPropertySymbol prop,
INamedTypeSymbol tupleType,
StringBuilder code,
INamedTypeSymbol classSymbol)
{
var parentType = classSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
var tupleElements = tupleType.TupleElements;
for (int i = 0; i < tupleElements.Length; i++)
{
var element = tupleElements[i];
var elementType = element.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
var elementName = element.Name;
// Getter保持不变
code.AppendLine(
$" public static {elementType} Get{prop.Name}_{elementName}" +
$"({parentType} obj) => obj.{prop.Name}.{elementName};");
// Setter修复:使用元组字面量
if (prop.SetMethod != null)
{
var valueExpressions = tupleElements.Select((e, idx) =>
idx == i ? "value" : $"obj.{prop.Name}.{e.Name}"
).ToList();
// 关键修复:生成正确的元组字面量表达式
code.AppendLine(
$" public static void Set{prop.Name}_{elementName}" +
$"({parentType} obj, {elementType} value) => " +
$"obj.{prop.Name} = ({string.Join(", ", valueExpressions)});");
}
}
}
///
/// 处理System.Tuple类型的访问器生成
///
private static void GenerateSystemTupleAccessors(
IPropertySymbol prop,
INamedTypeSymbol tupleType,
StringBuilder code,
INamedTypeSymbol classSymbol)
{
var parentType = classSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
var elementTypes = tupleType.TypeArguments;
var tupleTypeName = tupleType.ToDisplayString();
for (int i = 0; i < elementTypes.Length; i++)
{
var elementType = elementTypes[i].ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
var elementName = $"Item{i + 1}";
// 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)});");
}
}
}
///
/// 增强的工厂类实现
///
private static string BuildFactoryCode()
{
return """
using System;
using System.Collections.Concurrent;
using System.Reflection;
namespace JiShe.CollectBus.Analyzers.Shared;
public static class SourceEntityAccessorFactory
{
private static readonly ConcurrentDictionary _accessors = new();
public static ISourceEntityAccessor GetAccessor()
{
return (ISourceEntityAccessor)_accessors.GetOrAdd(typeof(T), t =>
{
// 获取泛型类型定义信息(如果是泛型类型)
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)
{
accessorType = accessorType.MakeGenericType(t.GetGenericArguments());
}
return Activator.CreateInstance(accessorType)!;
});
}
}
""";
}
///
/// 属性访问生成逻辑
///
/// 属性集合
///
///
///
private static void GetGeneratePropertyValueForSourceEntity(
IEnumerable propList,
StringBuilder code,
Compilation compilation,
INamedTypeSymbol classSymbol)
{
code.AppendLine($" public object GetPropertyValue({classSymbol} targetEntity, string propertyName)");
code.AppendLine(" {");
code.AppendLine(" return propertyName switch");
code.AppendLine(" {");
foreach (var prop in propList)
{
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),");
}
}
else
{
code.AppendLine(
$" \"{prop.Name}\" => " +
$"Get{prop.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} targetEntity, string propertyName, object value)");
code.AppendLine(" {");
code.AppendLine(" switch (propertyName)");
code.AppendLine(" {");
foreach (var prop in propList)
{
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;");
}
}
else if (prop.SetMethod != null)
{
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;");
}
}
code.AppendLine(" default:");
code.AppendLine(" throw new ArgumentException($\"Unknown property: {propertyName}\");");
code.AppendLine(" }");
code.AppendLine(" }");
}
///
/// 属性名称集合
///
/// 属性集合
///
///
///
private static void GeneratePropertyListForSourceEntity(
IEnumerable propList,
StringBuilder code,
Compilation compilation,
INamedTypeSymbol classSymbol)
{
code.AppendLine(" public List PropertyNameList {get;} = new List()");
code.AppendLine(" {");
List tempPropList = new List();
foreach (var prop in propList)
{
if (prop.Type is INamedTypeSymbol { IsTupleType: true } tupleType)
{
foreach (var element in tupleType.TupleElements)
{
tempPropList.Add($"\"{prop.Name}.{element.Name}\"");
}
}
else
{
tempPropList.Add($"\"{prop.Name}\"");
}
}
code.Append(string.Join(",", tempPropList));
code.AppendLine(" };");
}
///
/// 生成当前类属性信息集合(支持嵌套元组)
///
private static void GeneratePropertyInfoListForSourceEntity(
IEnumerable propList,
StringBuilder code,
Compilation compilation,
INamedTypeSymbol classSymbol)
{
code.AppendLine(" public List PropertyInfoList { get; } = new List");
code.AppendLine(" {");
var initializerLines = new List();
foreach (var prop in propList)
{
// 主属性
AddPropertyInitializer(classSymbol, prop, initializerLines);
// 处理元组嵌套属性
if (prop.Type is INamedTypeSymbol { IsTupleType: true } tupleType)
{
foreach (var element in tupleType.TupleElements)
{
// 生成形如:typeof(ValueTuple).GetProperty("Item1")
var tupleTypeName = tupleType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
initializerLines.Add(
$"typeof({tupleTypeName}).GetProperty(\"{element.Name}\") ?? " +
$"throw new InvalidOperationException(\"Tuple element {element.Name} not found\")");
}
}
}
code.AppendLine(string.Join(",\n", initializerLines));
code.AppendLine(" };");
}
private static void AddPropertyInitializer(
INamedTypeSymbol classSymbol,
IPropertySymbol prop,
List initializerLines)
{
var classType = classSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
initializerLines.Add(
$"typeof({classType}).GetProperty(\"{prop.Name}\", " +
"System.Reflection.BindingFlags.Public | " +
"System.Reflection.BindingFlags.Instance) ?? " +
$"throw new InvalidOperationException(\"Property {prop.Name} not found\")");
}
}
}