调整了Library文件结构;

源代码生成新增了参数验证方法;
修改了ParamterDetails的定义
This commit is contained in:
fengjiayi
2025-07-29 18:36:43 +08:00
parent b6ed0b69dc
commit 8dc7f5dd9b
20 changed files with 272 additions and 241 deletions

View File

@@ -0,0 +1,13 @@
namespace Serein.Library.Api
{
/// <summary>
/// 枚举转换器接口
/// </summary>
/// <typeparam name="TEnum"></typeparam>
/// <typeparam name="TValue"></typeparam>
public interface IEnumConvertor<TEnum, TValue>
{
TValue Convertor(TEnum e);
}
}

View File

@@ -0,0 +1,17 @@
using System;
namespace Serein.Library
{
/// <summary>
/// <para>表示该属性为自动注入依赖项。</para>
/// <para>使用场景:构造函数中存在互相依赖的情况</para>
/// <para>例如ServiceA类构造函数中需要传入ServiceBServiceB类构造函数中也需要传入ServiceA</para>
/// <para>这种情况会导致流程启动时IOC容器无法注入构造函数并创建类型导致启动失败。</para>
/// <para>解决方法从ServiceA类的构造函数中移除ServiceB类型的入参将该类型更改为公开可见的可写属性成员ServiceB serviceB{get;set;},并在该属性上标记[AutoInjection]特性</para>
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
public sealed class AutoInjectionAttribute : Attribute
{
}
}

View File

@@ -0,0 +1,26 @@
using Serein.Library;
using System;
namespace Serein.Library
{
/// <summary>
/// <para>启动流程时会将标记了该特性的类自动注册到IOC容器中从而无需手动进行注册绑定。</para>
/// <para>流程启动后IOC容器会进行5次注册绑定。</para>
/// <para>第1次注册绑定初始化所有节点所属的类[DynamicFlow]标记的类)。</para>
/// <para>第2次注册绑定※初始化所有[AutoRegister(Class=FlowInit)]的类。</para>
/// <para>第3次注册绑定调用所有Init节点后进行注册绑定。</para>
/// <para>第4次注册绑定※初始化所有[AutoRegister(Class=FlowLoading)]的类</para>
/// <para>第5次注册绑定调用所有Load节点后进行注册绑定。</para>
/// <para>需要注意的是在第1次进行注册绑定的过程中如果类的构造函数存在入参那么也会将入参自动创建实例并托管到IOC容器中。</para>
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public sealed class AutoRegisterAttribute : Attribute
{
public AutoRegisterAttribute(RegisterSequence Class = RegisterSequence.FlowInit)
{
this.Class = Class;
}
public RegisterSequence Class ;
}
}

View File

@@ -0,0 +1,21 @@
using System;
namespace Serein.Library
{
/// <summary>
/// 绑定转换器
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
public class BindConvertorAttribute : Attribute
{
public Type EnumType { get; }
public Type ConvertorType { get; }
public BindConvertorAttribute(Type @enum, Type convertor)
{
EnumType = @enum;
ConvertorType = convertor;
}
}
}

View File

@@ -0,0 +1,16 @@
using System;
namespace Serein.Library
{
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class BindValueAttribute : Attribute
{
public object Value { get; }
public BindValueAttribute(object value)
{
Value = value;
}
}
}

View File

@@ -0,0 +1,28 @@
using System;
using System.Text.RegularExpressions;
namespace Serein.Library
{
/// <summary>
/// <para>表示该类中存在节点信息</para>
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public sealed class DynamicFlowAttribute : Attribute
{
public DynamicFlowAttribute(string name = "",bool scan = true)
{
Name = name;
Scan = scan;
}
/// <summary>
/// 补充名称,不影响运行流程
/// </summary>
public string Name { get; set; }
/// <summary>
/// 如果设置为false将忽略该类
/// </summary>
public bool Scan { get; set; } = true;
}
}

View File

@@ -0,0 +1,27 @@
using System;
namespace Serein.Library
{
/// <summary>
/// 枚举值转换器要求枚举项标记的BindValueAttribute特性与搭配的参数类型一致否则参数不会传入
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
public class EnumTypeConvertorAttribute : Attribute
{
public Type EnumType { get; }
public EnumTypeConvertorAttribute(Type @enum)
{
if (@enum.IsEnum)
{
EnumType = @enum;
}
else
{
throw new ArgumentException("需要枚举类型");
}
}
}
}

View File

@@ -0,0 +1,44 @@
using System;
namespace Serein.Library
{
/// <summary>
/// <para>表示该方法将会生成节点,或是加入到流程运行中</para>
/// <para>如果是Task类型的返回值将会自动进行等待</para>
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public sealed class NodeActionAttribute : Attribute
{
public NodeActionAttribute(NodeType methodDynamicType,
string methodTips = "",
bool scan = true,
string lockName = "")
{
Scan = scan;
MethodDynamicType = methodDynamicType;
AnotherName = methodTips;
LockName = lockName;
}
/// <summary>
/// 如果设置为false时将不会生成节点信息
/// </summary>
public bool Scan;
/// <summary>
/// 类似于注释的效果
/// </summary>
public string AnotherName;
/// <summary>
/// 标记节点行为
/// </summary>
public NodeType MethodDynamicType;
/// <summary>
/// 暂无意义
/// </summary>
public string LockName;
/// <summary>
/// 分组名称,暂无意义
/// </summary>
public string GroupName;
}
}

View File

@@ -0,0 +1,24 @@
using System;
namespace Serein.Library
{
/// <summary>
/// 节点参数设置
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
public sealed class NodeParamAttribute : Attribute
{
/// <summary>
/// 显示名称
/// </summary>
public string Name;
/// <summary>
/// 是否显式设置(此设置对于有入参默认值的参数无效)
/// </summary>
public bool IsExplicit;
}
}

View File

@@ -0,0 +1,21 @@
namespace Serein.Library
{
/// <summary>
/// 注册顺序
/// </summary>
public enum RegisterSequence
{ /// <summary>
/// 不自动初始化
/// </summary>
Node,
/// <summary>
/// 初始化后
/// </summary>
FlowInit,
/// <summary>
/// 加载后
/// </summary>
FlowLoading,
}
}

View File

@@ -72,7 +72,6 @@ namespace Serein.Library
/// </summary>
[PropertyInfo]
private ParameterDetails[] _parameterDetailss;
//private List<ParameterDetails> _parameterDetailss;
/// <summary>
/// <para>描述该方法是否存在可选参数</para>

View File

@@ -36,7 +36,7 @@ namespace Serein.Library
/// <para>如果为 true ,则使用输入的文本值作为入参数据。</para>
/// <para>如果为 false ,则在当前流程上下文中,根据 ArgDataSourceNodeGuid 查找到对应节点,并根据 ArgDataSourceNodeGuid 判断如何获取其返回的数据,以此作为入参数据。</para>
/// </summary>
[PropertyInfo(IsNotification = true)]
[PropertyInfo(IsNotification = true, IsVerify = true)]
private bool _isExplicitData ;
///// <summary>
@@ -160,18 +160,18 @@ namespace Serein.Library
ExplicitType = Type.GetType(info.ExplicitTypeFullName);
InputType = info.InputType.ConvertEnum<ParameterValueInputType>();
Items = info.Items;
IsParams = info.IsParams;
IsParams = info.IsParams;
}
partial void OnIsExplicitDataChanged(bool oldValue, bool newValue)
partial void BeforeTheIsExplicitData(ref bool __isAllow, bool newValue)
{
if(DataType == typeof(IFlowContext))
{
__isAllow = false;
}
}
/// <summary>
/// 转为描述
/// </summary>

View File

@@ -1,202 +0,0 @@
using System;
using System.Text.RegularExpressions;
namespace Serein.Library
{
/// <summary>
/// <para>表示该属性为自动注入依赖项。</para>
/// <para>使用场景:构造函数中存在互相依赖的情况</para>
/// <para>例如ServiceA类构造函数中需要传入ServiceBServiceB类构造函数中也需要传入ServiceA</para>
/// <para>这种情况会导致流程启动时IOC容器无法注入构造函数并创建类型导致启动失败。</para>
/// <para>解决方法从ServiceA类的构造函数中移除ServiceB类型的入参将该类型更改为公开可见的可写属性成员ServiceB serviceB{get;set;},并在该属性上标记[AutoInjection]特性</para>
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
public sealed class AutoInjectionAttribute : Attribute
{
}
/// <summary>
/// 注册顺序
/// </summary>
public enum RegisterSequence
{ /// <summary>
/// 不自动初始化
/// </summary>
Node,
/// <summary>
/// 初始化后
/// </summary>
FlowInit,
/// <summary>
/// 加载后
/// </summary>
FlowLoading,
}
/// <summary>
/// <para>启动流程时会将标记了该特性的类自动注册到IOC容器中从而无需手动进行注册绑定。</para>
/// <para>流程启动后IOC容器会进行5次注册绑定。</para>
/// <para>第1次注册绑定初始化所有节点所属的类[DynamicFlow]标记的类)。</para>
/// <para>第2次注册绑定※初始化所有[AutoRegister(Class=FlowInit)]的类。</para>
/// <para>第3次注册绑定调用所有Init节点后进行注册绑定。</para>
/// <para>第4次注册绑定※初始化所有[AutoRegister(Class=FlowLoading)]的类</para>
/// <para>第5次注册绑定调用所有Load节点后进行注册绑定。</para>
/// <para>需要注意的是在第1次进行注册绑定的过程中如果类的构造函数存在入参那么也会将入参自动创建实例并托管到IOC容器中。</para>
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public sealed class AutoRegisterAttribute : Attribute
{
public AutoRegisterAttribute(RegisterSequence Class = RegisterSequence.FlowInit)
{
this.Class = Class;
}
public RegisterSequence Class ;
}
/// <summary>
/// <para>表示该类中存在节点信息</para>
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public sealed class DynamicFlowAttribute : Attribute
{
public DynamicFlowAttribute(string name = "",bool scan = true)
{
Name = name;
Scan = scan;
}
/// <summary>
/// 补充名称,不影响运行流程
/// </summary>
public string Name { get; set; }
/// <summary>
/// 如果设置为false将忽略该类
/// </summary>
public bool Scan { get; set; } = true;
}
/// <summary>
/// <para>表示该方法将会生成节点,或是加入到流程运行中</para>
/// <para>如果是Task类型的返回值将会自动进行等待</para>
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public sealed class NodeActionAttribute : Attribute
{
public NodeActionAttribute(NodeType methodDynamicType,
string methodTips = "",
bool scan = true,
string lockName = "")
{
Scan = scan;
MethodDynamicType = methodDynamicType;
AnotherName = methodTips;
LockName = lockName;
}
/// <summary>
/// 如果设置为false时将不会生成节点信息
/// </summary>
public bool Scan;
/// <summary>
/// 类似于注释的效果
/// </summary>
public string AnotherName;
/// <summary>
/// 标记节点行为
/// </summary>
public NodeType MethodDynamicType;
/// <summary>
/// 暂无意义
/// </summary>
public string LockName;
/// <summary>
/// 分组名称,暂无意义
/// </summary>
public string GroupName;
}
/// <summary>
/// 节点参数设置
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
public sealed class NodeParamAttribute : Attribute
{
/// <summary>
/// 显示名称
/// </summary>
public string Name;
/// <summary>
/// 是否显式设置(此设置对于有入参默认值的参数无效)
/// </summary>
public bool IsExplicit;
}
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class BindValueAttribute : Attribute
{
public object Value { get; }
public BindValueAttribute(object value)
{
Value = value;
}
}
/// <summary>
/// 枚举值转换器要求枚举项标记的BindValueAttribute特性与搭配的参数类型一致否则参数不会传入
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
public class EnumTypeConvertorAttribute : Attribute
{
public Type EnumType { get; }
public EnumTypeConvertorAttribute(Type @enum)
{
if (@enum.IsEnum)
{
EnumType = @enum;
}
else
{
throw new ArgumentException("需要枚举类型");
}
}
}
/// <summary>
/// 绑定转换器
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
public class BindConvertorAttribute : Attribute
{
public Type EnumType { get; }
public Type ConvertorType { get; }
public BindConvertorAttribute(Type @enum, Type convertor)
{
this.EnumType = @enum;
this.ConvertorType = convertor;
}
}
/// <summary>
/// 枚举转换器接口
/// </summary>
/// <typeparam name="TEnum"></typeparam>
/// <typeparam name="TValue"></typeparam>
public interface IEnumConvertor<TEnum, TValue>
{
TValue Convertor(TEnum e);
}
}

View File

@@ -7,6 +7,9 @@ using System.Threading.Tasks;
namespace Serein.Library
{
/// <summary>
/// 节点静态配置类
/// </summary>
public static class NodeStaticConfig
{
/// <summary>