完善增量源码生成器

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 System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Text;
@ -187,84 +188,72 @@ namespace JiShe.CollectBus.IncrementalGenerator
// 安全类型转换
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)
if (propType is INamedTypeSymbol namedType)
{
GenerateStandardAccessors(prop, namedType, code);
}
if (propType is INamedTypeSymbol { IsTupleType: true } tupleType)
{
GenerateTupleAccessors(prop, tupleType, code);
}
}
//生成当前类属性名称集合
GeneratePropertyListForSourceEntity(propList, code, compilation, classSymbol);
//生成当前类属性信息集合
GeneratePropertyInfoListForSourceEntity(
propList,
code,
compilation,
classSymbol);
GenerateEntityMemberInfoList(propList, code, compilation, classSymbol);
//生成当前类属性访问
GetGeneratePropertyValueForSourceEntity(
propList,
code,
compilation,
classSymbol);
GetGeneratePropertyValueForSourceEntity(propList, code, compilation, classSymbol);
//生成当前类属性设置
SetGeneratePropertyValueForSourceEntity(
propList,
code,
compilation,
classSymbol);
SetGeneratePropertyValueForSourceEntity(propList, code, compilation, classSymbol);
code.AppendLine("}");
return code.ToString();
}
/// <summary>
/// 生成泛型ValueTuple 元组访问器
/// </summary>
private static void GenerateTupleAccessors(
IPropertySymbol prop,
INamedTypeSymbol tupleType,
StringBuilder code,
INamedTypeSymbol classSymbol)
StringBuilder code)
{
var parentType = classSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
var parentType = prop.ContainingType.ToDisplayString();
var tupleElements = tupleType.TupleElements;
for (int i = 0; i < tupleElements.Length; i++)
{
var element = tupleElements[i];
var elementType = element.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
var elementType = element.Type.ToDisplayString();
var elementName = element.Name;
// Getter保持不变
code.AppendLine(
$" public static {elementType} Get{prop.Name}_{elementName}" +
$"({parentType} obj) => obj.{prop.Name}.{elementName};");
// Getter
code.AppendLine($"public static {elementType} Get{prop.Name}_{elementName}({parentType} obj) => obj.{prop.Name}.{elementName};");
// Setter修复:使用元组字面量
// 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)});");
code.AppendLine($"public static void Set{prop.Name}_{elementName}({parentType} obj, {elementType} value) => obj.{prop.Name} = ({string.Join(", ", GetTupleElements(prop.Name, tupleElements, i))});");
}
}
}
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>
/// 处理System.Tuple类型的访问器生成
/// </summary>
@ -370,6 +359,10 @@ namespace JiShe.CollectBus.IncrementalGenerator
foreach (var prop in propList)
{
code.AppendLine(
$" \"{prop.Name}\" => " +
$"Get{prop.Name}(targetEntity),");
if (prop.Type is INamedTypeSymbol { IsTupleType: true } tupleType)
{
foreach (var element in tupleType.TupleElements)
@ -379,12 +372,7 @@ namespace JiShe.CollectBus.IncrementalGenerator
$"Get{prop.Name}_{element.Name}(targetEntity),");
}
}
else
{
code.AppendLine(
$" \"{prop.Name}\" => " +
$"Get{prop.Name}(targetEntity),");
}
}
code.AppendLine(" _ => throw new ArgumentException($\"Unknown property: {propertyName}\")");
@ -412,6 +400,12 @@ namespace JiShe.CollectBus.IncrementalGenerator
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)
{
foreach (var element in tupleType.TupleElements)
@ -423,14 +417,6 @@ namespace JiShe.CollectBus.IncrementalGenerator
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:");
@ -477,33 +463,46 @@ namespace JiShe.CollectBus.IncrementalGenerator
/// <summary>
/// 生成当前类属性信息集合(支持嵌套元组)
/// 生成当前类属性信息集合
/// </summary>
private static void GeneratePropertyInfoListForSourceEntity(
private static void GenerateEntityMemberInfoList(
IEnumerable<IPropertySymbol> propList,
StringBuilder code,
Compilation compilation,
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(" {");
var initializerLines = new List<string>();
var index = 0;
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)
{
foreach (var element in tupleType.TupleElements)
{
//使用GetField代替GetProperty
var tupleTypeName = tupleType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
var elementType = element.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
var elementName = element.Name;
initializerLines.Add(
$"typeof({tupleTypeName}).GetField(\"{element.Name}\") ?? " +
$"throw new InvalidOperationException(\"Tuple field {element.Name} not found\")");
$"new EntityMemberInfo(" +
$"\"{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(" };");
}
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>();
foreach (var prop in accessor.PropertyInfoList)
foreach (var prop in accessor.MemberList)
{
string typeName = string.Empty;
Type declaredType = prop.PropertyType;
Type declaredType = prop.Type;
// 处理可空类型
if (declaredType.IsGenericType && declaredType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
@ -652,25 +652,25 @@ namespace JiShe.CollectBus.IoTDB.Provider
}
//先获取Tag标签和属性标签
ColumnInfo? column = prop.GetCustomAttribute<TAGColumnAttribute>() is not null ? new ColumnInfo(
name: prop.Name,
ColumnInfo? column = declaredType.GetCustomAttribute<TAGColumnAttribute>() is not null ? new ColumnInfo(
name: prop.Path,
category: ColumnCategory.TAG,
dataType: GetDataTypeFromTypeName(typeName),
false
) : prop.GetCustomAttribute<ATTRIBUTEColumnAttribute>() is not null ? new ColumnInfo(
prop.Name,
) : declaredType.GetCustomAttribute<ATTRIBUTEColumnAttribute>() is not null ? new ColumnInfo(
prop.Path,
ColumnCategory.ATTRIBUTE,
GetDataTypeFromTypeName(typeName),
false
) : prop.GetCustomAttribute<FIELDColumnAttribute>() is not null ? new ColumnInfo(
prop.Name,
) : declaredType.GetCustomAttribute<FIELDColumnAttribute>() is not null ? new ColumnInfo(
prop.Path,
ColumnCategory.FIELD,
GetDataTypeFromTypeName(typeName),
false)
: null;
//最先检查是不是单侧点模式
SingleMeasuringAttribute singleMeasuringAttribute = prop.GetCustomAttribute<SingleMeasuringAttribute>();
SingleMeasuringAttribute singleMeasuringAttribute = declaredType.GetCustomAttribute<SingleMeasuringAttribute>();
if (singleMeasuringAttribute != null && column == null)
{
@ -679,15 +679,15 @@ namespace JiShe.CollectBus.IoTDB.Provider
//只有一个Filed字段。
//MeasuringName 默认为 SingleMeasuringAttribute.FieldName以便于在获取对应的Value的时候重置为 Item1 的值。
Type tupleType = prop.PropertyType;
Type[] tupleArgs = tupleType.GetGenericArguments();
//Type tupleType = prop.PropertyType;
//Type[] tupleArgs = tupleType.GetGenericArguments();
column = new ColumnInfo(
singleMeasuringAttribute.FieldName,
ColumnCategory.FIELD,
GetDataTypeFromTypeName(tupleArgs[1].Name),
true
);
//column = new ColumnInfo(
// singleMeasuringAttribute.FieldName,
// ColumnCategory.FIELD,
// GetDataTypeFromTypeName(tupleArgs[1].Name),
// true
//);
}
if (column.HasValue)

View File

@ -32,11 +32,11 @@ namespace JiShe.CollectBus.Ammeters
public double Current { get; set; }
[FIELDColumn]
public double Power => Voltage * Current;
public double Power { get; set; }
[FIELDColumn]
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>
List<PropertyInfo> PropertyInfoList { get; }
List<EntityMemberInfo> MemberList { get; }
}
}