diff --git a/Library/Api/IEnumConvertor.cs b/Library/Api/IEnumConvertor.cs
new file mode 100644
index 0000000..d900d9b
--- /dev/null
+++ b/Library/Api/IEnumConvertor.cs
@@ -0,0 +1,13 @@
+namespace Serein.Library.Api
+{
+ ///
+ /// 枚举转换器接口
+ ///
+ ///
+ ///
+ public interface IEnumConvertor
+ {
+ TValue Convertor(TEnum e);
+ }
+
+}
diff --git a/Library/Attributes/AutoInjectionAttribute.cs b/Library/Attributes/AutoInjectionAttribute.cs
new file mode 100644
index 0000000..14be4dc
--- /dev/null
+++ b/Library/Attributes/AutoInjectionAttribute.cs
@@ -0,0 +1,17 @@
+using System;
+
+namespace Serein.Library
+{
+ ///
+ /// 表示该属性为自动注入依赖项。
+ /// 使用场景:构造函数中存在互相依赖的情况
+ /// 例如ServiceA类构造函数中需要传入ServiceB,ServiceB类构造函数中也需要传入ServiceA
+ /// 这种情况会导致流程启动时,IOC容器无法注入构造函数并创建类型,导致启动失败。
+ /// 解决方法:从ServiceA类的构造函数中移除ServiceB类型的入参,将该类型更改为公开可见的可写属性成员ServiceB serviceB{get;set;},并在该属性上标记[AutoInjection]特性
+ ///
+ [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
+ public sealed class AutoInjectionAttribute : Attribute
+ {
+ }
+
+}
diff --git a/Library/Attributes/AutoRegisterAttribute.cs b/Library/Attributes/AutoRegisterAttribute.cs
new file mode 100644
index 0000000..4ae3d34
--- /dev/null
+++ b/Library/Attributes/AutoRegisterAttribute.cs
@@ -0,0 +1,26 @@
+using Serein.Library;
+using System;
+
+namespace Serein.Library
+{
+ ///
+ /// 启动流程时,会将标记了该特性的类自动注册到IOC容器中,从而无需手动进行注册绑定。
+ /// 流程启动后,IOC容器会进行5次注册绑定。
+ /// 第1次注册绑定:初始化所有节点所属的类([DynamicFlow]标记的类)。
+ /// 第2次注册绑定:※初始化所有[AutoRegister(Class=FlowInit)]的类。
+ /// 第3次注册绑定:调用所有Init节点后,进行注册绑定。
+ /// 第4次注册绑定:※初始化所有[AutoRegister(Class=FlowLoading)]的类
+ /// 第5次注册绑定:调用所有Load节点后,进行注册绑定。
+ /// 需要注意的是,在第1次进行注册绑定的过程中,如果类的构造函数存在入参,那么也会将入参自动创建实例并托管到IOC容器中。
+ ///
+ [AttributeUsage(AttributeTargets.Class)]
+ public sealed class AutoRegisterAttribute : Attribute
+ {
+ public AutoRegisterAttribute(RegisterSequence Class = RegisterSequence.FlowInit)
+ {
+ this.Class = Class;
+ }
+ public RegisterSequence Class ;
+ }
+
+}
diff --git a/Library/Attributes/BindConvertorAttribute.cs b/Library/Attributes/BindConvertorAttribute.cs
new file mode 100644
index 0000000..04b6774
--- /dev/null
+++ b/Library/Attributes/BindConvertorAttribute.cs
@@ -0,0 +1,21 @@
+using System;
+
+namespace Serein.Library
+{
+ ///
+ /// 绑定转换器
+ ///
+ [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;
+ }
+ }
+
+}
diff --git a/Library/Attributes/BindValueAttribute.cs b/Library/Attributes/BindValueAttribute.cs
new file mode 100644
index 0000000..e963f6a
--- /dev/null
+++ b/Library/Attributes/BindValueAttribute.cs
@@ -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;
+ }
+ }
+
+}
diff --git a/Library/Attributes/DynamicFlowAttribute.cs b/Library/Attributes/DynamicFlowAttribute.cs
new file mode 100644
index 0000000..2512a9e
--- /dev/null
+++ b/Library/Attributes/DynamicFlowAttribute.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Text.RegularExpressions;
+
+namespace Serein.Library
+{
+
+ ///
+ /// 表示该类中存在节点信息
+ ///
+ [AttributeUsage(AttributeTargets.Class)]
+ public sealed class DynamicFlowAttribute : Attribute
+ {
+ public DynamicFlowAttribute(string name = "",bool scan = true)
+ {
+ Name = name;
+ Scan = scan;
+ }
+ ///
+ /// 补充名称,不影响运行流程
+ ///
+ public string Name { get; set; }
+ ///
+ /// 如果设置为false,将忽略该类
+ ///
+ public bool Scan { get; set; } = true;
+ }
+
+}
diff --git a/Library/Attributes/EnumTypeConvertorAttribute.cs b/Library/Attributes/EnumTypeConvertorAttribute.cs
new file mode 100644
index 0000000..c0f40c9
--- /dev/null
+++ b/Library/Attributes/EnumTypeConvertorAttribute.cs
@@ -0,0 +1,27 @@
+using System;
+
+namespace Serein.Library
+{
+ ///
+ /// 枚举值转换器,要求枚举项标记的BindValueAttribute特性,与搭配的参数类型一致,否则参数不会传入
+ ///
+
+ [AttributeUsage(AttributeTargets.Parameter)]
+ public class EnumTypeConvertorAttribute : Attribute
+ {
+ public Type EnumType { get; }
+
+ public EnumTypeConvertorAttribute(Type @enum)
+ {
+ if (@enum.IsEnum)
+ {
+ EnumType = @enum;
+ }
+ else
+ {
+ throw new ArgumentException("需要枚举类型");
+ }
+ }
+ }
+
+}
diff --git a/Library/Attributes/NodeActionAttribute.cs b/Library/Attributes/NodeActionAttribute.cs
new file mode 100644
index 0000000..aff2ecd
--- /dev/null
+++ b/Library/Attributes/NodeActionAttribute.cs
@@ -0,0 +1,44 @@
+using System;
+
+namespace Serein.Library
+{
+ ///
+ /// 表示该方法将会生成节点,或是加入到流程运行中
+ /// 如果是Task类型的返回值,将会自动进行等待
+ ///
+ [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;
+ }
+ ///
+ /// 如果设置为false时将不会生成节点信息
+ ///
+ public bool Scan;
+ ///
+ /// 类似于注释的效果
+ ///
+ public string AnotherName;
+ ///
+ /// 标记节点行为
+ ///
+ public NodeType MethodDynamicType;
+ ///
+ /// 暂无意义
+ ///
+ public string LockName;
+ ///
+ /// 分组名称,暂无意义
+ ///
+ public string GroupName;
+ }
+
+}
diff --git a/Library/Attributes/NodeParamAttribute.cs b/Library/Attributes/NodeParamAttribute.cs
new file mode 100644
index 0000000..486f8f7
--- /dev/null
+++ b/Library/Attributes/NodeParamAttribute.cs
@@ -0,0 +1,24 @@
+using System;
+
+namespace Serein.Library
+{
+ ///
+ /// 节点参数设置
+ ///
+ [AttributeUsage(AttributeTargets.Parameter)]
+ public sealed class NodeParamAttribute : Attribute
+ {
+ ///
+ /// 显示名称
+ ///
+ public string Name;
+
+ ///
+ /// 是否显式设置(此设置对于有入参默认值的参数无效)
+ ///
+ public bool IsExplicit;
+
+
+ }
+
+}
diff --git a/Library/Enums/RegisterSequence.cs b/Library/Enums/RegisterSequence.cs
new file mode 100644
index 0000000..7b60023
--- /dev/null
+++ b/Library/Enums/RegisterSequence.cs
@@ -0,0 +1,21 @@
+namespace Serein.Library
+{
+ ///
+ /// 注册顺序
+ ///
+ public enum RegisterSequence
+ { ///
+ /// 不自动初始化
+ ///
+ Node,
+ ///
+ /// 初始化后
+ ///
+ FlowInit,
+ ///
+ /// 加载后
+ ///
+ FlowLoading,
+ }
+
+}
diff --git a/Library/FlowNode/MethodDetails.cs b/Library/FlowNode/MethodDetails.cs
index 4a6001f..5a5b532 100644
--- a/Library/FlowNode/MethodDetails.cs
+++ b/Library/FlowNode/MethodDetails.cs
@@ -72,7 +72,6 @@ namespace Serein.Library
///
[PropertyInfo]
private ParameterDetails[] _parameterDetailss;
- //private List _parameterDetailss;
///
/// 描述该方法是否存在可选参数
diff --git a/Library/FlowNode/ParameterDetails.cs b/Library/FlowNode/ParameterDetails.cs
index 056c089..37f0765 100644
--- a/Library/FlowNode/ParameterDetails.cs
+++ b/Library/FlowNode/ParameterDetails.cs
@@ -36,7 +36,7 @@ namespace Serein.Library
/// 如果为 true ,则使用输入的文本值作为入参数据。
/// 如果为 false ,则在当前流程上下文中,根据 ArgDataSourceNodeGuid 查找到对应节点,并根据 ArgDataSourceNodeGuid 判断如何获取其返回的数据,以此作为入参数据。
///
- [PropertyInfo(IsNotification = true)]
+ [PropertyInfo(IsNotification = true, IsVerify = true)]
private bool _isExplicitData ;
/////
@@ -160,18 +160,18 @@ namespace Serein.Library
ExplicitType = Type.GetType(info.ExplicitTypeFullName);
InputType = info.InputType.ConvertEnum();
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;
}
}
+
///
/// 转为描述
///
diff --git a/Library/NodeAttribute.cs b/Library/NodeAttribute.cs
deleted file mode 100644
index 4eadefc..0000000
--- a/Library/NodeAttribute.cs
+++ /dev/null
@@ -1,202 +0,0 @@
-using System;
-using System.Text.RegularExpressions;
-
-namespace Serein.Library
-{
- ///
- /// 表示该属性为自动注入依赖项。
- /// 使用场景:构造函数中存在互相依赖的情况
- /// 例如ServiceA类构造函数中需要传入ServiceB,ServiceB类构造函数中也需要传入ServiceA
- /// 这种情况会导致流程启动时,IOC容器无法注入构造函数并创建类型,导致启动失败。
- /// 解决方法:从ServiceA类的构造函数中移除ServiceB类型的入参,将该类型更改为公开可见的可写属性成员ServiceB serviceB{get;set;},并在该属性上标记[AutoInjection]特性
- ///
- [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
- public sealed class AutoInjectionAttribute : Attribute
- {
- }
-
-
- ///
- /// 注册顺序
- ///
- public enum RegisterSequence
- { ///
- /// 不自动初始化
- ///
- Node,
- ///
- /// 初始化后
- ///
- FlowInit,
- ///
- /// 加载后
- ///
- FlowLoading,
- }
-
-
- ///
- /// 启动流程时,会将标记了该特性的类自动注册到IOC容器中,从而无需手动进行注册绑定。
- /// 流程启动后,IOC容器会进行5次注册绑定。
- /// 第1次注册绑定:初始化所有节点所属的类([DynamicFlow]标记的类)。
- /// 第2次注册绑定:※初始化所有[AutoRegister(Class=FlowInit)]的类。
- /// 第3次注册绑定:调用所有Init节点后,进行注册绑定。
- /// 第4次注册绑定:※初始化所有[AutoRegister(Class=FlowLoading)]的类
- /// 第5次注册绑定:调用所有Load节点后,进行注册绑定。
- /// 需要注意的是,在第1次进行注册绑定的过程中,如果类的构造函数存在入参,那么也会将入参自动创建实例并托管到IOC容器中。
- ///
- [AttributeUsage(AttributeTargets.Class)]
- public sealed class AutoRegisterAttribute : Attribute
- {
- public AutoRegisterAttribute(RegisterSequence Class = RegisterSequence.FlowInit)
- {
- this.Class = Class;
- }
- public RegisterSequence Class ;
- }
-
- ///
- /// 表示该类中存在节点信息
- ///
- [AttributeUsage(AttributeTargets.Class)]
- public sealed class DynamicFlowAttribute : Attribute
- {
- public DynamicFlowAttribute(string name = "",bool scan = true)
- {
- Name = name;
- Scan = scan;
- }
- ///
- /// 补充名称,不影响运行流程
- ///
- public string Name { get; set; }
- ///
- /// 如果设置为false,将忽略该类
- ///
- public bool Scan { get; set; } = true;
- }
-
-
-
- ///
- /// 表示该方法将会生成节点,或是加入到流程运行中
- /// 如果是Task类型的返回值,将会自动进行等待
- ///
- [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;
- }
- ///
- /// 如果设置为false时将不会生成节点信息
- ///
- public bool Scan;
- ///
- /// 类似于注释的效果
- ///
- public string AnotherName;
- ///
- /// 标记节点行为
- ///
- public NodeType MethodDynamicType;
- ///
- /// 暂无意义
- ///
- public string LockName;
- ///
- /// 分组名称,暂无意义
- ///
- public string GroupName;
- }
-
-
- ///
- /// 节点参数设置
- ///
- [AttributeUsage(AttributeTargets.Parameter)]
- public sealed class NodeParamAttribute : Attribute
- {
- ///
- /// 显示名称
- ///
- public string Name;
-
- ///
- /// 是否显式设置(此设置对于有入参默认值的参数无效)
- ///
- public bool IsExplicit;
-
-
- }
-
-
- [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
- public class BindValueAttribute : Attribute
- {
- public object Value { get; }
-
- public BindValueAttribute(object value)
- {
- Value = value;
- }
- }
-
-
-
- ///
- /// 枚举值转换器,要求枚举项标记的BindValueAttribute特性,与搭配的参数类型一致,否则参数不会传入
- ///
-
- [AttributeUsage(AttributeTargets.Parameter)]
- public class EnumTypeConvertorAttribute : Attribute
- {
- public Type EnumType { get; }
-
- public EnumTypeConvertorAttribute(Type @enum)
- {
- if (@enum.IsEnum)
- {
- EnumType = @enum;
- }
- else
- {
- throw new ArgumentException("需要枚举类型");
- }
- }
- }
-
- ///
- /// 绑定转换器
- ///
- [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;
- }
- }
-
- ///
- /// 枚举转换器接口
- ///
- ///
- ///
- public interface IEnumConvertor
- {
- TValue Convertor(TEnum e);
- }
-
-}
diff --git a/Library/NodeStaticConfig.cs b/Library/NodeStaticConfig.cs
index c3b8ff2..bd92b86 100644
--- a/Library/NodeStaticConfig.cs
+++ b/Library/NodeStaticConfig.cs
@@ -7,6 +7,9 @@ using System.Threading.Tasks;
namespace Serein.Library
{
+ ///
+ /// 节点静态配置类
+ ///
public static class NodeStaticConfig
{
///
diff --git a/NodeFlow/FlowWorkOptions.cs b/NodeFlow/FlowWorkOptions.cs
index a144006..171c7af 100644
--- a/NodeFlow/FlowWorkOptions.cs
+++ b/NodeFlow/FlowWorkOptions.cs
@@ -1,11 +1,5 @@
-using Microsoft.Extensions.ObjectPool;
-using Serein.Library;
+using Serein.Library;
using Serein.Library.Api;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
namespace Serein.NodeFlow
{
diff --git a/NodeFlow/Model/Librarys/FlowLibraryCache.cs b/NodeFlow/Model/Librarys/FlowLibraryCache.cs
index fff9e40..58fb0f9 100644
--- a/NodeFlow/Model/Librarys/FlowLibraryCache.cs
+++ b/NodeFlow/Model/Librarys/FlowLibraryCache.cs
@@ -1,16 +1,6 @@
using Serein.Library;
-using Serein.Library.Utils;
using Serein.NodeFlow.Tool;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Globalization;
-using System.IO;
-using System.Linq;
using System.Reflection;
-using System.Text;
-using static System.Runtime.InteropServices.JavaScript.JSType;
namespace Serein.NodeFlow.Model.Library
{
diff --git a/NodeFlow/Services/FlowLibraryService.cs b/NodeFlow/Services/FlowLibraryService.cs
index 4dcd363..b99ae75 100644
--- a/NodeFlow/Services/FlowLibraryService.cs
+++ b/NodeFlow/Services/FlowLibraryService.cs
@@ -1,17 +1,10 @@
using Serein.Library;
using Serein.Library.Api;
-using Serein.Library.FlowNode;
-using Serein.Library.Utils;
using Serein.NodeFlow.Model.Library;
using Serein.NodeFlow.Tool;
-using System;
using System.Collections.Concurrent;
-using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
-using System.Linq;
using System.Reflection;
-using System.Text;
-using System.Threading.Tasks;
using System.Xml.Linq;
namespace Serein.NodeFlow.Services
diff --git a/NodeFlow/Tool/NodeMethodDetailsHelper.cs b/NodeFlow/Tool/NodeMethodDetailsHelper.cs
index a6e884b..681757f 100644
--- a/NodeFlow/Tool/NodeMethodDetailsHelper.cs
+++ b/NodeFlow/Tool/NodeMethodDetailsHelper.cs
@@ -1,13 +1,9 @@
-using Serein.Library.Api;
-using Serein.Library.Utils;
-using Serein.Library;
+using Serein.Library;
+using Serein.Library.Api;
using System.Collections.Concurrent;
-using System.Reflection;
-using Serein.Library.FlowNode;
-using System.Diagnostics;
-using System.Diagnostics.CodeAnalysis;
-using System.ComponentModel.DataAnnotations;
using System.ComponentModel;
+using System.Diagnostics.CodeAnalysis;
+using System.Reflection;
namespace Serein.NodeFlow.Tool;
diff --git a/Serein.Library.MyGenerator/Attribute.cs b/Serein.Library.MyGenerator/Attribute.cs
index 0d47c83..acec5db 100644
--- a/Serein.Library.MyGenerator/Attribute.cs
+++ b/Serein.Library.MyGenerator/Attribute.cs
@@ -69,6 +69,14 @@ namespace Serein.Library
/// 是否禁止参数进行修改(初始化后不能再通过 Setter 修改)
///
public bool IsProtection = false;
+
+ ///
+ /// 是否需要验证参数
+ ///
+ public bool IsVerify = false;
+
+
+
/*
///
/// 自定义代码(属性变更前)
diff --git a/Serein.Library.MyGenerator/ParameterDetailsPropertyGenerator.cs b/Serein.Library.MyGenerator/ParameterDetailsPropertyGenerator.cs
index 8e550f5..218b484 100644
--- a/Serein.Library.MyGenerator/ParameterDetailsPropertyGenerator.cs
+++ b/Serein.Library.MyGenerator/ParameterDetailsPropertyGenerator.cs
@@ -146,9 +146,17 @@ namespace Serein.Library.NodeGenerator
var attributeInfo = fieldKV.Value; // 缓存的特性信息
var isProtection = attributeInfo.Search(nameof(PropertyInfo), nameof(PropertyInfo.IsProtection), value => bool.Parse(value)); // 是否为保护字段
+ var isVerify = attributeInfo.Search(nameof(PropertyInfo), nameof(PropertyInfo.IsVerify), value => bool.Parse(value)); // 是否为保护字段
+
//sb.AppendLine(leadingTrivia);
sb.AppendLine($" partial void On{propertyName}Changed({fieldType} oldValue, {fieldType} newValue);");
sb.AppendLine($" partial void On{propertyName}Changed({fieldType} value);");
+
+ if (isVerify)
+ {
+ sb.AppendLine($" partial void BeforeThe{propertyName}(ref bool __isAllow, {fieldType} newValue);");
+ }
+
if (isProtection)
{
sb.AppendLine($" private bool __{propertyName}ProtectionField = false;");
@@ -164,7 +172,12 @@ namespace Serein.Library.NodeGenerator
sb.AppendLine( " set");
sb.AppendLine( " {");
//sb.AppendLine($" if ({fieldName} {(isProtection ? "== default" : "!= value")})"); // 非保护的Setter
-
+ if (isVerify)
+ {
+ sb.AppendLine($" bool __isAllow = true;");
+ sb.AppendLine($" BeforeThe{propertyName}(ref __isAllow, value);");
+ sb.AppendLine($" if(!__isAllow) return; // 修改验证失败");
+ }
sb.AppendLine($" var __oldValue = {fieldName};");
if (isProtection)
{