完善增量源码生成器

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;
@ -187,84 +188,72 @@ namespace JiShe.CollectBus.IncrementalGenerator
// 安全类型转换 // 安全类型转换
if (prop.Type is not ITypeSymbol propType) continue; if (prop.Type is not ITypeSymbol propType) continue;
if (propType is INamedTypeSymbol { IsTupleType: true } tupleType) if (propType is INamedTypeSymbol namedType)
{
GenerateTupleAccessors(prop, tupleType, code, classSymbol);
}
else if (propType is INamedTypeSymbol namedType)
{ {
GenerateStandardAccessors(prop, namedType, code); GenerateStandardAccessors(prop, namedType, code);
} }
if (propType is INamedTypeSymbol { IsTupleType: true } tupleType)
{
GenerateTupleAccessors(prop, tupleType, code);
}
} }
//生成当前类属性名称集合 //生成当前类属性名称集合
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)
@ -423,14 +417,6 @@ namespace JiShe.CollectBus.IncrementalGenerator
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:");
@ -477,33 +463,46 @@ 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))");
} }
} }
} }
@ -511,18 +510,5 @@ namespace JiShe.CollectBus.IncrementalGenerator
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

@ -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; }
} }
} }