@ -1,5 +1,6 @@
using Microsoft.CodeAnalysis ;
using Microsoft.CodeAnalysis.CSharp.Syntax ;
using System ;
using System.Collections.Generic ;
using System.Diagnostics ;
using System.Linq ;
@ -8,7 +9,7 @@ using System.Text;
namespace JiShe.CollectBus.IncrementalGenerator
{
/// <summary>
/// 复杂类型 源生成器
/// 复杂类型 增量 源生成器
/// </summary>
[Generator(LanguageNames.CSharp)]
public class ComplexTypeSourceAnalyzers : IIncrementalGenerator
@ -107,43 +108,13 @@ namespace JiShe.CollectBus.IncrementalGenerator
continue ;
}
//context.ReportDiagnostic(Diagnostic.Create(
//new DiagnosticDescriptor(
// "PA001",
// "Generated Accessors",
// $"Generating accessors for {classSymbol.Name}",
// "Performance",
// DiagnosticSeverity.Info,
// true),
//Location.None));
//// 新增:输出继承链信息
//context.ReportDiagnostic(Diagnostic.Create(
// new DiagnosticDescriptor("HIERARCHY", "Class Hierarchy",
// $"Processing class: {classSymbol.Name}, BaseType: {classSymbol.BaseType?.Name}",
// "Debug", DiagnosticSeverity.Info, true),
// Location.None));
//context.ReportDiagnostic(Diagnostic.Create(
//new DiagnosticDescriptor("PA002", "Class Found",
//$"Processing class: {classSymbol.Name}", "Debug", DiagnosticSeverity.Warning, true),
//Location.None));
var code = BuildAccessorsForType ( classSymbol , compilation , processedTypes ) ;
//System.Diagnostics.Debug.WriteLine($"Generated code for {classSymbol.Name}:\n{code}"); // 调试输出
context . AddSource ( $"{classSymbol.Name}Extension.g.cs" , code ) ;
var code3 = BuildAccessorsFor Type2 ( classSymbol , compilation , processedTypes ) ;
var code3 = BuildAccessorsForSourceEntity ( classSymbol , compilation , processedTypes ) ;
context . AddSource ( $"{classSymbol.Name}Accessor.g.cs" , code3 ) ;
//code.AppendLine($"namespace {classSymbol.ContainingNamespace.ToDisplayString()};");
//if (classSymbol.ContainingNamespace.ToDisplayString() == "JiShe.CollectBus.IoTDB")
//{
//}
}
// 生成工厂注册代码
@ -183,52 +154,6 @@ namespace JiShe.CollectBus.IncrementalGenerator
return code . ToString ( ) ;
}
/// <summary>
/// 构建类的属性访问器代码
/// </summary>
/// <param name="classSymbol"></param>
/// <param name="compilation"></param>
/// <param name="processedTypes"></param>
/// <returns></returns>
private static string BuildAccessorsForType2 (
INamedTypeSymbol classSymbol ,
Compilation compilation ,
HashSet < ITypeSymbol > processedTypes )
{
var code = new StringBuilder ( ) ;
code . AppendLine ( "#pragma warning disable CS0419 // 禁用警告" ) ;
code . AppendLine ( "// Generated code for " + classSymbol . Name ) ;
code . AppendLine ( "// <auto-generated/>" ) ;
code . AppendLine ( "#nullable enable" ) ;
code . AppendLine ( $"namespace {classSymbol.ContainingNamespace.ToDisplayString()};" ) ;
code . AppendLine ( ) ;
code . AppendLine ( $"public sealed class {classSymbol.Name}Accessor : ISourceEntityAccessor<{classSymbol.Name}>" ) ;
code . AppendLine ( "{" ) ;
foreach ( var prop in GetAllPropertiesInHierarchy ( classSymbol ) )
{
if ( prop . IsIndexer ) continue ;
GeneratePropertyAccessorsForType ( prop , code , compilation , processedTypes ) ;
}
code . AppendLine ( "}" ) ;
//var code3 = $@"
// public sealed class {classSymbol.Name}Accessor : ISourceEntityAccessor<{classSymbol.Name}>
// {{
// public object GetPropertyValue({classSymbol.Name} entity, string propName) => propName switch
// {{
// {GeneratePropertyCases(classSymbol)}
// _ => throw new ArgumentException(""无效属性名"")
// }};
// {GenerateTupleSupport(classSymbol)}
// }}";
return code . ToString ( ) ;
}
/// <summary>
/// 获取泛型参数
/// </summary>
@ -262,11 +187,11 @@ namespace JiShe.CollectBus.IncrementalGenerator
// 处理元组类型
if ( propType is INamedTypeSymbol { IsTupleType : true } tupleType )
{
GenerateTupleAccessors ( prop , tupleType , code ) ;
GenerateTupleAccessors ForType ( prop , tupleType , code ) ;
}
else if ( propType is INamedTypeSymbol namedType )
{
GenerateStandardAccessors ( prop , namedType , code ) ;
GenerateStandardAccessors ForType ( prop , namedType , code ) ;
ProcessNestedType ( namedType , compilation , processedTypes ) ;
}
}
@ -277,7 +202,7 @@ namespace JiShe.CollectBus.IncrementalGenerator
/// <param name="prop"></param>
/// <param name="tupleType"></param>
/// <param name="code"></param>
private static void GenerateTupleAccessors ( IPropertySymbol prop , INamedTypeSymbol tupleType , StringBuilder code )
private static void GenerateTupleAccessors ForType ( IPropertySymbol prop , INamedTypeSymbol tupleType , StringBuilder code )
{
var elements = tupleType . TupleElements ;
var parentType = prop . ContainingType . ToDisplayString ( ) ;
@ -305,7 +230,7 @@ namespace JiShe.CollectBus.IncrementalGenerator
/// <param name="prop"></param>
/// <param name="propType"></param>
/// <param name="code"></param>
private static void GenerateStandardAccessors ( IPropertySymbol prop , INamedTypeSymbol propType , StringBuilder code )
private static void GenerateStandardAccessors ForType ( 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};" ) ;
@ -373,5 +298,153 @@ namespace JiShe.CollectBus.IncrementalGenerator
}
"" ";
}
/// <summary>
/// 构建实体类的源属性访问器代码
/// </summary>
/// <param name="classSymbol"></param>
/// <param name="compilation"></param>
/// <param name="processedTypes"></param>
/// <returns></returns>
private static string BuildAccessorsForSourceEntity (
INamedTypeSymbol classSymbol ,
Compilation compilation ,
HashSet < ITypeSymbol > processedTypes )
{
var code = new StringBuilder ( ) ;
code . AppendLine ( "#pragma warning disable CS0419 // 禁用警告" ) ;
code . AppendLine ( "// Generated code for " + classSymbol . Name ) ;
code . AppendLine ( "// <auto-generated/>" ) ;
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 < IPropertySymbol > 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 < IPropertySymbol > 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 ( " }" ) ;
}
/// <summary>
/// 处理元组类型
/// </summary>
/// <param name="prop"></param>
/// <param name="tupleType"></param>
/// <param name="code"></param>
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)});" ) ;
}
}
}
/// <summary>
/// 生成标准属性的访问器
/// </summary>
/// <param name="prop"></param>
/// <param name="propType"></param>
/// <param name="code"></param>
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;" ) ;
}
}
}
}