完善增量源码生成器

This commit is contained in:
ChenYi 2025-05-08 11:17:43 +08:00
parent edecbc386e
commit db7384ae74
5 changed files with 96 additions and 110 deletions

View File

@ -2,6 +2,7 @@
using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Syntax;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@ -105,7 +106,7 @@ namespace JiShe.CollectBus.IncrementalGenerator
Location.None)); Location.None));
continue; continue;
} }
var code3 = BuildAccessorsForSourceEntity(classSymbol, compilation, processedTypes); var code3 = BuildAccessorsForSourceEntity(classSymbol, compilation, processedTypes);
context.AddSource($"{classSymbol.Name}Accessor.g.cs", code3); context.AddSource($"{classSymbol.Name}Accessor.g.cs", code3);
} }
@ -113,7 +114,7 @@ namespace JiShe.CollectBus.IncrementalGenerator
// 生成工厂注册代码 // 生成工厂注册代码
context.AddSource("SourceEntityAccessorFactory.g.cs", BuildFactoryCode()); context.AddSource("SourceEntityAccessorFactory.g.cs", BuildFactoryCode());
} }
/// <summary> /// <summary>
/// 获取泛型参数 /// 获取泛型参数
/// </summary> /// </summary>
@ -125,8 +126,8 @@ namespace JiShe.CollectBus.IncrementalGenerator
var parameters = symbol.TypeParameters.Select(t => t.Name); var parameters = symbol.TypeParameters.Select(t => t.Name);
return $"<{string.Join(", ", parameters)}>"; return $"<{string.Join(", ", parameters)}>";
} }
/// <summary> /// <summary>
/// 生成标准属性的访问器 /// 生成标准属性的访问器
/// </summary> /// </summary>
@ -143,7 +144,7 @@ namespace JiShe.CollectBus.IncrementalGenerator
code.AppendLine($" public static void Set{prop.Name}({parentType} obj, {propType.ToDisplayString()} value) => obj.{prop.Name} = value;"); code.AppendLine($" public static void Set{prop.Name}({parentType} obj, {propType.ToDisplayString()} value) => obj.{prop.Name} = value;");
} }
} }
/// <summary> /// <summary>
/// 构建实体访问器代码(支持泛型) /// 构建实体访问器代码(支持泛型)
@ -179,21 +180,22 @@ namespace JiShe.CollectBus.IncrementalGenerator
$": ISourceEntityAccessor<{classSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}>"); $": ISourceEntityAccessor<{classSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}>");
code.AppendLine("{"); code.AppendLine("{");
var propList = GetAllPropertiesInHierarchy(classSymbol); var propList = GetAllPropertiesInHierarchy(classSymbol);
foreach (var prop in propList) foreach (var prop in propList)
{ {
// 安全类型转换 // 安全类型转换
if (prop.Type is not ITypeSymbol propType) continue; if (prop.Type is not ITypeSymbol propType) continue;
if (propType is INamedTypeSymbol namedType)
{
GenerateStandardAccessors(prop, namedType, code);
}
if (propType is INamedTypeSymbol { IsTupleType: true } tupleType) if (propType is INamedTypeSymbol { IsTupleType: true } tupleType)
{ {
GenerateTupleAccessors(prop, tupleType, code, classSymbol); GenerateTupleAccessors(prop, tupleType, code);
}
else if (propType is INamedTypeSymbol namedType)
{
GenerateStandardAccessors(prop, namedType, code);
} }
} }
@ -201,70 +203,57 @@ namespace JiShe.CollectBus.IncrementalGenerator
GeneratePropertyListForSourceEntity(propList, code, compilation, classSymbol); GeneratePropertyListForSourceEntity(propList, code, compilation, classSymbol);
//生成当前类属性信息集合 //生成当前类属性信息集合
GeneratePropertyInfoListForSourceEntity( GenerateEntityMemberInfoList(propList, code, compilation, classSymbol);
propList,
code,
compilation,
classSymbol);
//生成当前类属性访问 //生成当前类属性访问
GetGeneratePropertyValueForSourceEntity( GetGeneratePropertyValueForSourceEntity(propList, code, compilation, classSymbol);
propList,
code,
compilation,
classSymbol);
//生成当前类属性设置 //生成当前类属性设置
SetGeneratePropertyValueForSourceEntity( SetGeneratePropertyValueForSourceEntity(propList, code, compilation, classSymbol);
propList,
code,
compilation,
classSymbol);
code.AppendLine("}"); code.AppendLine("}");
return code.ToString(); return code.ToString();
} }
/// <summary>
/// 生成泛型ValueTuple 元组访问器
/// </summary>
private static void GenerateTupleAccessors( private static void GenerateTupleAccessors(
IPropertySymbol prop, IPropertySymbol prop,
INamedTypeSymbol tupleType, INamedTypeSymbol tupleType,
StringBuilder code, StringBuilder code)
INamedTypeSymbol classSymbol)
{ {
var parentType = classSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); var parentType = prop.ContainingType.ToDisplayString();
var tupleElements = tupleType.TupleElements; var tupleElements = tupleType.TupleElements;
for (int i = 0; i < tupleElements.Length; i++) for (int i = 0; i < tupleElements.Length; i++)
{ {
var element = tupleElements[i]; var element = tupleElements[i];
var elementType = element.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); var elementType = element.Type.ToDisplayString();
var elementName = element.Name; var elementName = element.Name;
// Getter保持不变 // Getter
code.AppendLine( code.AppendLine($"public static {elementType} Get{prop.Name}_{elementName}({parentType} obj) => obj.{prop.Name}.{elementName};");
$" public static {elementType} Get{prop.Name}_{elementName}" +
$"({parentType} obj) => obj.{prop.Name}.{elementName};");
// Setter修复:使用元组字面量 // Setter
if (prop.SetMethod != null) if (prop.SetMethod != null)
{ {
var valueExpressions = tupleElements.Select((e, idx) => code.AppendLine($"public static void Set{prop.Name}_{elementName}({parentType} obj, {elementType} value) => obj.{prop.Name} = ({string.Join(", ", GetTupleElements(prop.Name, tupleElements, i))});");
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)});");
} }
} }
} }
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}";
}
}
/// <summary> /// <summary>
/// 处理System.Tuple类型的访问器生成 /// 处理System.Tuple类型的访问器生成
/// </summary> /// </summary>
@ -370,6 +359,10 @@ namespace JiShe.CollectBus.IncrementalGenerator
foreach (var prop in propList) foreach (var prop in propList)
{ {
code.AppendLine(
$" \"{prop.Name}\" => " +
$"Get{prop.Name}(targetEntity),");
if (prop.Type is INamedTypeSymbol { IsTupleType: true } tupleType) if (prop.Type is INamedTypeSymbol { IsTupleType: true } tupleType)
{ {
foreach (var element in tupleType.TupleElements) foreach (var element in tupleType.TupleElements)
@ -379,12 +372,7 @@ namespace JiShe.CollectBus.IncrementalGenerator
$"Get{prop.Name}_{element.Name}(targetEntity),"); $"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(" _ => throw new ArgumentException($\"Unknown property: {propertyName}\")");
@ -412,6 +400,12 @@ namespace JiShe.CollectBus.IncrementalGenerator
foreach (var prop in propList) foreach (var prop in propList)
{ {
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;");
if (prop.Type is INamedTypeSymbol { IsTupleType: true } tupleType) if (prop.Type is INamedTypeSymbol { IsTupleType: true } tupleType)
{ {
foreach (var element in tupleType.TupleElements) foreach (var element in tupleType.TupleElements)
@ -422,15 +416,7 @@ namespace JiShe.CollectBus.IncrementalGenerator
code.AppendLine($" targetEntity, ({elementType})value);"); code.AppendLine($" targetEntity, ({elementType})value);");
code.AppendLine(" break;"); 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(" default:");
@ -458,7 +444,7 @@ namespace JiShe.CollectBus.IncrementalGenerator
foreach (var prop in propList) foreach (var prop in propList)
{ {
if (prop.Type is INamedTypeSymbol { IsTupleType: true } tupleType) if (prop.Type is INamedTypeSymbol { IsTupleType: true } tupleType)
{ {
foreach (var element in tupleType.TupleElements) foreach (var element in tupleType.TupleElements)
{ {
tempPropList.Add($"\"{prop.Name}.{element.Name}\""); tempPropList.Add($"\"{prop.Name}.{element.Name}\"");
@ -477,52 +463,52 @@ namespace JiShe.CollectBus.IncrementalGenerator
/// <summary> /// <summary>
/// 生成当前类属性信息集合(支持嵌套元组) /// 生成当前类属性信息集合
/// </summary> /// </summary>
private static void GeneratePropertyInfoListForSourceEntity( private static void GenerateEntityMemberInfoList(
IEnumerable<IPropertySymbol> propList, IEnumerable<IPropertySymbol> propList,
StringBuilder code, StringBuilder code,
Compilation compilation, Compilation compilation,
INamedTypeSymbol classSymbol) INamedTypeSymbol classSymbol)
{ {
code.AppendLine(" public List<System.Reflection.PropertyInfo> PropertyInfoList { get; } = new List<System.Reflection.PropertyInfo>"); code.AppendLine(" public List<EntityMemberInfo> MemberList { get; } = new()");
code.AppendLine(" {"); code.AppendLine(" {");
var initializerLines = new List<string>(); var initializerLines = new List<string>();
var index = 0;
foreach (var prop in propList) foreach (var prop in propList)
{ {
AddPropertyInitializer(classSymbol, prop, initializerLines); var propType = prop.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
var parentType = prop.ContainingType.ToDisplayString();
// 主属性
initializerLines.Add(
$"new EntityMemberInfo(" +
$"\"{prop.Name}\", " +
$"typeof({parentType}), " +
$"(e) => Get{prop.Name}(({parentType})e), " +
$"(e, v) => Set{prop.Name}(({parentType})e, ({propType})v))");
// 元组元素
if (prop.Type is INamedTypeSymbol { IsTupleType: true } tupleType) if (prop.Type is INamedTypeSymbol { IsTupleType: true } tupleType)
{ {
foreach (var element in tupleType.TupleElements) foreach (var element in tupleType.TupleElements)
{ {
//使用GetField代替GetProperty var elementType = element.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
var tupleTypeName = tupleType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); var elementName = element.Name;
initializerLines.Add( initializerLines.Add(
$"typeof({tupleTypeName}).GetField(\"{element.Name}\") ?? " + $"new EntityMemberInfo(" +
$"throw new InvalidOperationException(\"Tuple field {element.Name} not found\")"); $"\"{prop.Name}.{elementName}\", " +
$"typeof({elementType}), " +
$"(e) => Get{prop.Name}_{elementName}(({parentType})e), " +
$"(e, v) => Set{prop.Name}_{elementName}(({parentType})e, ({elementType})v))");
} }
} }
} }
code.AppendLine(string.Join(",\n", initializerLines)); code.AppendLine(string.Join(",\n", initializerLines));
code.AppendLine(" };"); code.AppendLine(" };");
} }
private static void AddPropertyInitializer(
INamedTypeSymbol classSymbol,
IPropertySymbol prop,
List<string> 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\")");
}
} }
} }

View File

@ -635,11 +635,11 @@ namespace JiShe.CollectBus.IoTDB.Provider
{ {
var columns = new List<ColumnInfo>(); var columns = new List<ColumnInfo>();
foreach (var prop in accessor.PropertyInfoList) foreach (var prop in accessor.MemberList)
{ {
string typeName = string.Empty; string typeName = string.Empty;
Type declaredType = prop.PropertyType; Type declaredType = prop.Type;
// 处理可空类型 // 处理可空类型
if (declaredType.IsGenericType && declaredType.GetGenericTypeDefinition() == typeof(Nullable<>)) if (declaredType.IsGenericType && declaredType.GetGenericTypeDefinition() == typeof(Nullable<>))
{ {
@ -652,25 +652,25 @@ namespace JiShe.CollectBus.IoTDB.Provider
} }
//先获取Tag标签和属性标签 //先获取Tag标签和属性标签
ColumnInfo? column = prop.GetCustomAttribute<TAGColumnAttribute>() is not null ? new ColumnInfo( ColumnInfo? column = declaredType.GetCustomAttribute<TAGColumnAttribute>() is not null ? new ColumnInfo(
name: prop.Name, name: prop.Path,
category: ColumnCategory.TAG, category: ColumnCategory.TAG,
dataType: GetDataTypeFromTypeName(typeName), dataType: GetDataTypeFromTypeName(typeName),
false false
) : prop.GetCustomAttribute<ATTRIBUTEColumnAttribute>() is not null ? new ColumnInfo( ) : declaredType.GetCustomAttribute<ATTRIBUTEColumnAttribute>() is not null ? new ColumnInfo(
prop.Name, prop.Path,
ColumnCategory.ATTRIBUTE, ColumnCategory.ATTRIBUTE,
GetDataTypeFromTypeName(typeName), GetDataTypeFromTypeName(typeName),
false false
) : prop.GetCustomAttribute<FIELDColumnAttribute>() is not null ? new ColumnInfo( ) : declaredType.GetCustomAttribute<FIELDColumnAttribute>() is not null ? new ColumnInfo(
prop.Name, prop.Path,
ColumnCategory.FIELD, ColumnCategory.FIELD,
GetDataTypeFromTypeName(typeName), GetDataTypeFromTypeName(typeName),
false) false)
: null; : null;
//最先检查是不是单侧点模式 //最先检查是不是单侧点模式
SingleMeasuringAttribute singleMeasuringAttribute = prop.GetCustomAttribute<SingleMeasuringAttribute>(); SingleMeasuringAttribute singleMeasuringAttribute = declaredType.GetCustomAttribute<SingleMeasuringAttribute>();
if (singleMeasuringAttribute != null && column == null) if (singleMeasuringAttribute != null && column == null)
{ {
@ -679,15 +679,15 @@ namespace JiShe.CollectBus.IoTDB.Provider
//只有一个Filed字段。 //只有一个Filed字段。
//MeasuringName 默认为 SingleMeasuringAttribute.FieldName以便于在获取对应的Value的时候重置为 Item1 的值。 //MeasuringName 默认为 SingleMeasuringAttribute.FieldName以便于在获取对应的Value的时候重置为 Item1 的值。
Type tupleType = prop.PropertyType; //Type tupleType = prop.PropertyType;
Type[] tupleArgs = tupleType.GetGenericArguments(); //Type[] tupleArgs = tupleType.GetGenericArguments();
column = new ColumnInfo( //column = new ColumnInfo(
singleMeasuringAttribute.FieldName, // singleMeasuringAttribute.FieldName,
ColumnCategory.FIELD, // ColumnCategory.FIELD,
GetDataTypeFromTypeName(tupleArgs[1].Name), // GetDataTypeFromTypeName(tupleArgs[1].Name),
true // true
); //);
} }
if (column.HasValue) if (column.HasValue)

View File

@ -75,7 +75,7 @@ public class SampleAppService : CollectBusAppService, ISampleAppService, IKafkaS
//ElectricityMeterTreeModelAccessor. //ElectricityMeterTreeModelAccessor.
//TableModelSingleMeasuringEntityExtension //TableModelSingleMeasuringEntityExtension
//TableModelSingleMeasuringEntityAccessor.GetSystemName(meter); //TableModelSingleMeasuringEntityAccessor.GetSystemName(meter);
await _iotDBProvider.InsertAsync(meter); await _iotDBProvider.InsertAsync(meter);
} }

View File

@ -32,11 +32,11 @@ namespace JiShe.CollectBus.Ammeters
public double Current { get; set; } public double Current { get; set; }
[FIELDColumn] [FIELDColumn]
public double Power => Voltage * Current; public double Power { get; set; }
[FIELDColumn] [FIELDColumn]
public double? Currentd { get; set; } public double? Currentd { get; set; }
public Tuple<int,string> TupleData { get; set;} public ValueTuple<int, string> TupleData { get; set; }
} }
} }

View File

@ -31,6 +31,6 @@ namespace JiShe.CollectBus.Analyzers.Shared
/// <summary> /// <summary>
/// 属性信息集合 /// 属性信息集合
/// </summary> /// </summary>
List<PropertyInfo> PropertyInfoList { get; } List<EntityMemberInfo> MemberList { get; }
} }
} }