优化增量源码生成器和IoTDB驱动

This commit is contained in:
ChenYi 2025-05-08 14:42:13 +08:00
parent db7384ae74
commit c03207aa21
16 changed files with 276 additions and 122 deletions

View File

@ -183,6 +183,9 @@ namespace JiShe.CollectBus.IncrementalGenerator
var propList = GetAllPropertiesInHierarchy(classSymbol);
//类名称
code.AppendLine($" public string EntityName {{get;}} = \"{classSymbol.Name}\";");
foreach (var prop in propList)
{
// 安全类型转换
@ -216,6 +219,12 @@ namespace JiShe.CollectBus.IncrementalGenerator
return code.ToString();
}
/// <summary>
/// 生成ValueTuple元组属性访问器
/// </summary>
/// <param name="prop"></param>
/// <param name="tupleType"></param>
/// <param name="code"></param>
private static void GenerateTupleAccessors(
IPropertySymbol prop,
INamedTypeSymbol tupleType,
@ -475,21 +484,39 @@ namespace JiShe.CollectBus.IncrementalGenerator
code.AppendLine(" {");
var initializerLines = new List<string>();
var index = 0;
foreach (var prop in propList)
{
var propType = prop.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
var parentType = prop.ContainingType.ToDisplayString();
// 主属性
initializerLines.Add(
// 处理主属性
var propAttributes = prop.GetAttributes()
.Where(a => !IsCompilerGeneratedAttribute(a))
.ToList();
var attributeInitializers = propAttributes
.Select(GenerateAttributeInitializer)
.Where(s => !string.IsNullOrEmpty(s));
var mainMember = new StringBuilder();
mainMember.Append(
$"new EntityMemberInfo(" +
$"\"{prop.Name}\", " +
$"typeof({parentType}), " +
$"typeof({propType}), " +
$"(e) => Get{prop.Name}(({parentType})e), " +
$"(e, v) => Set{prop.Name}(({parentType})e, ({propType})v))");
// 元组元素
if (attributeInitializers.Any())
{
mainMember.AppendLine();
mainMember.Append(" { CustomAttributes = new List<Attribute>");
mainMember.Append($" {{ {string.Join(", ", attributeInitializers)} }} }}");
}
initializerLines.Add(mainMember.ToString());
// 处理元组元素(假设不需要处理元组元素的特性)
if (prop.Type is INamedTypeSymbol { IsTupleType: true } tupleType)
{
foreach (var element in tupleType.TupleElements)
@ -510,5 +537,89 @@ namespace JiShe.CollectBus.IncrementalGenerator
code.AppendLine(string.Join(",\n", initializerLines));
code.AppendLine(" };");
}
private static string GenerateAttributeInitializer(AttributeData attribute)
{
if (attribute.AttributeClass == null)
return string.Empty;
var attributeClass = attribute.AttributeClass.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
var args = attribute.ConstructorArguments;
var namedArgs = attribute.NamedArguments;
var parameters = new List<string>();
foreach (var arg in args)
{
parameters.Add(ConvertTypedConstantToCode(arg));
}
var constructorArgs = string.Join(", ", parameters);
var initializer = new StringBuilder();
initializer.Append($"new {attributeClass}({constructorArgs})");
if (namedArgs.Any())
{
initializer.Append(" { ");
var namedArgsList = namedArgs.Select(n => $"{n.Key} = {ConvertTypedConstantToCode(n.Value)}");
initializer.Append(string.Join(", ", namedArgsList));
initializer.Append(" }");
}
return initializer.ToString();
}
private static string ConvertTypedConstantToCode(TypedConstant constant)
{
if (constant.IsNull)
return "null";
switch (constant.Kind)
{
case TypedConstantKind.Array:
var elements = constant.Values.Select(ConvertTypedConstantToCode);
return $"new[] {{ {string.Join(", ", elements)} }}";
case TypedConstantKind.Type:
var typeSymbol = (ITypeSymbol)constant.Value!;
return $"typeof({typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)})";
case TypedConstantKind.Enum:
return ConvertEnumTypedConstant(constant);
default:
return ConvertPrimitiveConstant(constant);
}
}
private static string ConvertEnumTypedConstant(TypedConstant constant)
{
var enumType = constant.Type!;
var enumValue = constant.Value!;
var enumTypeName = enumType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
foreach (var member in enumType.GetMembers().OfType<IFieldSymbol>())
{
if (member.ConstantValue != null && member.ConstantValue.Equals(enumValue))
return $"{enumTypeName}.{member.Name}";
}
return $"({enumTypeName})({enumValue})";
}
private static string ConvertPrimitiveConstant(TypedConstant constant)
{
var value = constant.Value!;
return value switch
{
string s => $"\"{s}\"",
char c => $"'{c}'",
bool b => b ? "true" : "false",
_ => value.ToString()
};
}
private static bool IsCompilerGeneratedAttribute(AttributeData attribute)
{
return attribute.AttributeClass?.ToDisplayString() == "System.Runtime.CompilerServices.CompilerGeneratedAttribute";
}
}
}

View File

@ -1,4 +1,4 @@
namespace JiShe.CollectBus.IoTDB.Attribute
namespace JiShe.CollectBus.IoTDB.Attributes
{
/// <summary>
/// Column分类标记特性ATTRIBUTE字段,也就是属性字段

View File

@ -1,6 +1,6 @@
using JiShe.CollectBus.IoTDB.Enums;
namespace JiShe.CollectBus.IoTDB.Attribute
namespace JiShe.CollectBus.IoTDB.Attributes
{
/// <summary>
/// IoTDB实体类型特性

View File

@ -1,4 +1,4 @@
namespace JiShe.CollectBus.IoTDB.Attribute
namespace JiShe.CollectBus.IoTDB.Attributes
{
/// <summary>
/// Column分类标记特性FIELD字段数据列字段

View File

@ -1,4 +1,4 @@
namespace JiShe.CollectBus.IoTDB.Attribute
namespace JiShe.CollectBus.IoTDB.Attributes
{
/// <summary>
/// 用于标识当前实体为单侧点模式单侧点模式只有一个Filed标识字段,类型是Tuple<string,T>,Item1=>测点名称Item2=>测点值,泛型

View File

@ -1,4 +1,4 @@
namespace JiShe.CollectBus.IoTDB.Attribute
namespace JiShe.CollectBus.IoTDB.Attributes
{
/// <summary>
/// Column分类标记特性TAG字段标签字段

View File

@ -1,6 +1,6 @@
using JiShe.CollectBus.IoTDB.Enums;
namespace JiShe.CollectBus.IoTDB.Attribute
namespace JiShe.CollectBus.IoTDB.Attributes
{
/// <summary>
/// IoTDB实体存储路径或表名称一般用于已经明确的存储路径或表名称例如日志存储

View File

@ -1,5 +1,5 @@
using JiShe.CollectBus.Common.Attributes;
using JiShe.CollectBus.IoTDB.Attribute;
using JiShe.CollectBus.IoTDB.Attributes;
namespace JiShe.CollectBus.IoTDB.Model
{

View File

@ -1,5 +1,5 @@
using JiShe.CollectBus.Analyzers.Shared;
using JiShe.CollectBus.IoTDB.Attribute;
using JiShe.CollectBus.IoTDB.Attributes;
using JiShe.CollectBus.IoTDB.Enums;
namespace JiShe.CollectBus.IoTDB.Model

View File

@ -1,5 +1,5 @@
using JiShe.CollectBus.Analyzers.Shared;
using JiShe.CollectBus.IoTDB.Attribute;
using JiShe.CollectBus.IoTDB.Attributes;
using JiShe.CollectBus.IoTDB.Enums;
namespace JiShe.CollectBus.IoTDB.Model

View File

@ -12,7 +12,7 @@ using JiShe.CollectBus.Common.Enums;
using JiShe.CollectBus.Common.Extensions;
using JiShe.CollectBus.Common.Helpers;
using JiShe.CollectBus.Common.Models;
using JiShe.CollectBus.IoTDB.Attribute;
using JiShe.CollectBus.IoTDB.Attributes;
using JiShe.CollectBus.IoTDB.Context;
using JiShe.CollectBus.IoTDB.Interface;
using JiShe.CollectBus.IoTDB.Model;
@ -635,43 +635,56 @@ namespace JiShe.CollectBus.IoTDB.Provider
{
var columns = new List<ColumnInfo>();
foreach (var prop in accessor.MemberList)
foreach (var member in accessor.MemberList)
{
string typeName = string.Empty;
//元组的子项字段详情不处理。
if (member.NameOrPath.Contains(".Item"))
{
continue;
}
string declaredTypeName = string.Empty;
Type declaredType = member.DeclaredType;//属性的类型如stringint等
Type declaredType = prop.Type;
// 处理可空类型
if (declaredType.IsGenericType && declaredType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
Type underlyingType = Nullable.GetUnderlyingType(declaredType);
typeName = underlyingType.Name;
declaredTypeName = underlyingType.Name;
}
else
{
typeName = declaredType.Name;
declaredTypeName = member.NameOrPath;
}
var tagAttr = member.CustomAttributes?.OfType<TAGColumnAttribute>().FirstOrDefault();
var attrColumn = member.CustomAttributes?.OfType<ATTRIBUTEColumnAttribute>().FirstOrDefault();
var fieldColumn = member.CustomAttributes?.OfType<FIELDColumnAttribute>().FirstOrDefault();
//判断是否是单测数据
var singleMeasuringAttribute = member.CustomAttributes?.OfType<SingleMeasuringAttribute>().FirstOrDefault();
//先获取Tag标签和属性标签
ColumnInfo? column = declaredType.GetCustomAttribute<TAGColumnAttribute>() is not null ? new ColumnInfo(
name: prop.Path,
ColumnInfo? column = tagAttr != null ? new ColumnInfo(
name: member.NameOrPath,
category: ColumnCategory.TAG,
dataType: GetDataTypeFromTypeName(typeName),
dataType: GetDataTypeFromTypeName(declaredTypeName),
false
) : declaredType.GetCustomAttribute<ATTRIBUTEColumnAttribute>() is not null ? new ColumnInfo(
prop.Path,
) : attrColumn != null ? new ColumnInfo(
member.NameOrPath,
ColumnCategory.ATTRIBUTE,
GetDataTypeFromTypeName(typeName),
GetDataTypeFromTypeName(declaredTypeName),
false
) : declaredType.GetCustomAttribute<FIELDColumnAttribute>() is not null ? new ColumnInfo(
prop.Path,
) : fieldColumn != null ? new ColumnInfo(
member.NameOrPath,
ColumnCategory.FIELD,
GetDataTypeFromTypeName(typeName),
GetDataTypeFromTypeName(declaredTypeName),
false)
: null;
//最先检查是不是单侧点模式
SingleMeasuringAttribute singleMeasuringAttribute = declaredType.GetCustomAttribute<SingleMeasuringAttribute>();
//检查是不是单侧点模式
if (singleMeasuringAttribute != null && column == null)
{
//warning: 单侧点模式注意事项
@ -679,15 +692,19 @@ namespace JiShe.CollectBus.IoTDB.Provider
//只有一个Filed字段。
//MeasuringName 默认为 SingleMeasuringAttribute.FieldName以便于在获取对应的Value的时候重置为 Item1 的值。
//Type tupleType = prop.PropertyType;
//Type[] tupleArgs = tupleType.GetGenericArguments();
Type tupleType = accessor.MemberList.Where(d => d.NameOrPath == $"{member.NameOrPath}.Item2").FirstOrDefault()?.DeclaredType;
//column = new ColumnInfo(
// singleMeasuringAttribute.FieldName,
// ColumnCategory.FIELD,
// GetDataTypeFromTypeName(tupleArgs[1].Name),
// true
//);
if (tupleType == null)
{
throw new Exception($"{nameof(CollectColumnMetadata)} {accessor.EntityName} {member.NameOrPath} 属性解析异常");
}
column = new ColumnInfo(
member.NameOrPath,
ColumnCategory.FIELD,
GetDataTypeFromTypeName(tupleType.Name),
true
);
}
if (column.HasValue)

View File

@ -1,12 +1,12 @@
using JiShe.CollectBus.Analyzers.Shared;
using JiShe.CollectBus.IoTDB.Attribute;
using JiShe.CollectBus.IoTDB.Attributes;
using JiShe.CollectBus.IoTDB.Enums;
using JiShe.CollectBus.IoTDB.Model;
namespace JiShe.CollectBus.Ammeters
{
[EntityType(EntityTypeEnum.TableModel)]
//[SourceAnalyzers]
[SourceAnalyzers]
public class ElectricityMeter : IoTEntity
{
[ATTRIBUTEColumn]
@ -31,7 +31,7 @@ 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; }

View File

@ -1,5 +1,5 @@
using JiShe.CollectBus.Analyzers.Shared;
using JiShe.CollectBus.IoTDB.Attribute;
using JiShe.CollectBus.IoTDB.Attributes;
using JiShe.CollectBus.IoTDB.Enums;
using JiShe.CollectBus.IoTDB.Model;
using System;

View File

@ -1,5 +1,5 @@
using JiShe.CollectBus.Analyzers.Shared;
using JiShe.CollectBus.IoTDB.Attribute;
using JiShe.CollectBus.IoTDB.Attributes;
using JiShe.CollectBus.IoTDB.Enums;
using JiShe.CollectBus.IoTDB.Model;
using System;

View File

@ -9,24 +9,45 @@ namespace JiShe.CollectBus.Analyzers.Shared
/// </summary>
public sealed class EntityMemberInfo
{
public string Path { get; set; }
public Type Type { get; set; }
private readonly Func<object, object> _getter;
private readonly Action<object, object> _setter;
/// <summary>
/// 名称或者路径
/// </summary>
public string NameOrPath { get; set; }
/// <summary>
/// 声明的类型
/// </summary>
public Type DeclaredType { get; set; }
/// <summary>
/// 获取值
/// </summary>
public Func<object, object> Getter { get; }
/// <summary>
/// 设置值
/// </summary>
public Action<object, object> Setter { get; }
/// <summary>
/// 自定义Attribute集合
/// </summary>
public List<Attribute> CustomAttributes { get; set; }
public EntityMemberInfo(
string path,
Type type,
string nameOrPath,
Type declaredType,
Func<object, object> getter,
Action<object, object> setter)
{
Path = path;
Type = type;
_getter = getter;
_setter = setter;
NameOrPath = nameOrPath;
this.DeclaredType = declaredType;
Getter = getter;
Setter = setter;
}
public object GetValue(object entity) => _getter(entity);
public void SetValue(object entity, object value) => _setter(entity, value);
public object GetValue(object entity) => Getter(entity);
public void SetValue(object entity, object value) => Setter(entity, value);
}
}

View File

@ -7,6 +7,11 @@ namespace JiShe.CollectBus.Analyzers.Shared
{
public interface ISourceEntityAccessor<T>
{
/// <summary>
/// 实体类名称
/// </summary>
string EntityName { get; }
/// <summary>
/// 获取属性值
/// </summary>