From 5bef0d9b570829ad43d73f7cef0638f9cbe97a61 Mon Sep 17 00:00:00 2001 From: fengjiayi <12821976+ning_xi@user.noreply.gitee.com> Date: Fri, 11 Oct 2024 19:31:34 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A1=A5=E5=85=85=E4=BA=86Library=E7=9A=84?= =?UTF-8?q?=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Library/Api/IDynamicContext.cs | 4 +- Library/Api/IDynamicFlowNode.cs | 3 + Library/Api/IFlipflopContext.cs | 4 +- Library/Api/ISereinIoc.cs | 57 +++++---- Library/Entity/CallChainInfo.cs | 18 --- Library/Entity/DelegateDetails.cs | 10 +- Library/Entity/ExplicitData.cs | 4 +- Library/Entity/MethodDetails.cs | 114 +----------------- Library/Entity/NodeData.cs | 10 -- Library/Entity/NodeDebugSetting.cs | 17 +-- Library/Entity/NodeLibrary.cs | 7 ++ Library/Entity/SereinProjectData.cs | 18 +-- Library/Enums/ConnectionType.cs | 6 +- Library/Enums/FlipflopStateType.cs | 6 +- Library/Enums/NodeType.cs | 44 ++++++- Library/Ex/FlipflopException.cs | 20 ++- Library/Utils/ConvertHelper.cs | 3 + Library/Utils/EmitHelper.cs | 17 ++- Library/Utils/EnumHelper.cs | 35 +++++- Library/Utils/ExpressionHelper.cs | 2 +- Library/Utils/SereinIoc.cs | 9 +- Net462DllTest/LogicControl/PlcLogicControl.cs | 8 +- .../LogicControl/ViewLogicControl.cs | 13 +- Net462DllTest/Web/FlowController.cs | 2 +- NodeFlow/FlowEnvironment.cs | 6 +- NodeFlow/FlowStarter.cs | 2 +- NodeFlow/Model/SingleFlipflopNode.cs | 2 +- 27 files changed, 202 insertions(+), 239 deletions(-) delete mode 100644 Library/Entity/CallChainInfo.cs delete mode 100644 Library/Entity/NodeData.cs diff --git a/Library/Api/IDynamicContext.cs b/Library/Api/IDynamicContext.cs index aabb395..31d5b74 100644 --- a/Library/Api/IDynamicContext.cs +++ b/Library/Api/IDynamicContext.cs @@ -5,12 +5,12 @@ using System.Threading.Tasks; namespace Serein.Library.Api { /// - /// 流程上下文 + /// 流程上下文,包含运行环境接口,可以通过注册环境事件或调用环境接口,实现在流程运行时更改流程行为。 /// public interface IDynamicContext { /// - /// 运行环境 + /// 运行环境,包含IOC容器。 /// IFlowEnvironment Env { get; } diff --git a/Library/Api/IDynamicFlowNode.cs b/Library/Api/IDynamicFlowNode.cs index 1cf5511..683b215 100644 --- a/Library/Api/IDynamicFlowNode.cs +++ b/Library/Api/IDynamicFlowNode.cs @@ -6,6 +6,9 @@ using System.Threading.Tasks; namespace Serein.Library.Api { + /// + /// 空接口 + /// public interface IDynamicFlowNode { } diff --git a/Library/Api/IFlipflopContext.cs b/Library/Api/IFlipflopContext.cs index 36134f3..39cdb22 100644 --- a/Library/Api/IFlipflopContext.cs +++ b/Library/Api/IFlipflopContext.cs @@ -4,7 +4,9 @@ using Serein.Library.NodeFlow.Tool; namespace Serein.Library.Api { /// - /// 触发器必须使用该接口作为返回值,同时必须用Task泛型表示,否则将不会进行等待触发。 + /// 触发器必须使用该接口作为返回值,同时必须用Task泛型表示,否则将不会进行等待触发。 + /// 即使大多数时候,触发器传出的数据可能是任何一种数据类型,导致其泛型参数可能是无意义的 object / dynamic 。 + /// 但在确定传出类型的场景下,至少可以保证数据一定为某个类型。 /// public interface IFlipflopContext { diff --git a/Library/Api/ISereinIoc.cs b/Library/Api/ISereinIoc.cs index 7f22dcc..b7491a1 100644 --- a/Library/Api/ISereinIoc.cs +++ b/Library/Api/ISereinIoc.cs @@ -4,19 +4,23 @@ using System.Text; namespace Serein.Library.Api { + /// + /// 单例模式IOC容器,内部维护了一个实例字典,默认使用类型的FullName作为Key,如果以“接口-实现类”的方式注册,那么将使用接口类型的FullName作为Key。 + /// 当某个类型注册绑定成功后,将不会因为其它地方尝试注册相同类型的行为导致类型被重新创建。 + /// public interface ISereinIOC { /// - /// 清空 + /// 慎用,重置IOC容器,除非再次注册绑定,否则将导致不能创建注入依赖类的临时对象。 /// /// ISereinIOC Reset(); /// - /// 注册实例 + /// 注册实例,如果确定了params,那么将使用params入参构建实例对象。 /// ISereinIOC Register(Type type, params object[] parameters); /// - /// 注册实例 + /// 通过泛型的方式注册实例,如果确定了params,那么将使用params入参构建实例对象。 /// /// /// @@ -25,58 +29,65 @@ namespace Serein.Library.Api /// /// 注册接口的实例 /// - /// - /// + /// 接口类型 + /// 实例类型 /// /// ISereinIOC Register(params object[] parameters) where TImplementation : TService; - ///// - ///// 获取或创建并注入目标类型,会记录到IOC容器中。 - ///// - //T GetOrRegisterInstantiate(); - ///// - ///// 获取或创建并注入目标类型,会记录到IOC容器中。 - ///// - //object GetOrRegisterInstantiate(Type type); /// - /// 获取类型的实例 + /// 获取类型的实例。如果需要获取的类型以“接口-实现类”的方式注册,请使用接口的类型。 /// - /// - /// object Get(Type type); + /// + /// 获取类型的实例。如果需要获取的类型以“接口-实现类”的方式注册,请使用接口的类型。 + /// T Get(); /// - /// 获取指定名称的实例 + /// 获取指定名称的实例。 + /// 正常情况下应该使用 Get(Type type) / T Get<T>() 进行获取,但如果需要的实例是以CustomRegisterInstance()进行的登记,则需要通过这种方法进行获取。 /// /// - /// + /// 登记实例时使用的Key /// T Get(string key); /// - /// 通过名称注册实例 + /// 指定一个Key登记一个实例。如果实例中需要注入的依赖项,需要将needInjectProperty设置为true。 /// /// 注入名称 /// 实例对象 /// 是否需要注入依赖项 - void CustomRegisterInstance(string key, object instance, bool needInjectProperty = true); + /// 是否注册成功 + bool CustomRegisterInstance(string key, object instance, bool needInjectProperty = true); /// - /// 用于临时实例的创建,不注册到IOC容器中,依赖项注入失败时也不记录。 + /// 创建实例并注入依赖项,不会注册到IOC容器中。 + /// 使用场景:例如 View 的构造函数中需要创建 ViewModel,而 ViewModel 存在注册过的依赖项,可以通过该接口进行创建 + /// /// object Instantiate(Type type); + /// - /// 用于临时实例的创建,不注册到IOC容器中,依赖项注入失败时也不记录。 + /// 创建实例并注入依赖项,不会注册到IOC容器中。 + /// 使用场景:例如 View 的构造函数中需要创建 ViewModel,而 ViewModel 存在注册过的依赖项,可以通过该接口进行创建 + /// /// T Instantiate(); + /// - /// 实例化注册的类型,并注入依赖项 + /// 通过已注册的类型,生成依赖关系,然后依次实例化并注入依赖项,最后登记到容器中。 /// /// ISereinIOC Build(); + /// + /// 从容器中获取某个类型的实例进行运行 + /// + /// + /// + /// ISereinIOC Run(Action action); ISereinIOC Run(Action action); ISereinIOC Run(Action action); diff --git a/Library/Entity/CallChainInfo.cs b/Library/Entity/CallChainInfo.cs deleted file mode 100644 index fe47b13..0000000 --- a/Library/Entity/CallChainInfo.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Serein.Library.Entity -{ - // 每次发生调用的时候,将当前节点调用信息拷贝一份, - // 调用完成后释放? - // 参数信息 - public class CallChainInfo - { - public List CallGuid { get; } - public List InvokeData { get; } - public List ResultData { get; } - } - - -} diff --git a/Library/Entity/DelegateDetails.cs b/Library/Entity/DelegateDetails.cs index 824e820..dc4412b 100644 --- a/Library/Entity/DelegateDetails.cs +++ b/Library/Entity/DelegateDetails.cs @@ -9,7 +9,8 @@ using static Serein.Library.Utils.EmitHelper; namespace Serein.Library.Entity { /// - /// 委托描述 + /// Emit创建的委托描述,用于WebApi、WebSocket、NodeFlow动态调用方法的场景。 + /// 一般情况下你无须内部细节,只需要调用 Invoke() 方法即可。 /// public class DelegateDetails { @@ -28,6 +29,13 @@ namespace Serein.Library.Entity public Delegate EmitDelegate { get => _emitDelegate; } public EmitMethodType EmitMethodType { get => _emitMethodType; } + /// + /// 异步等待Emit创建的委托。 + /// 需要注意的是,传入的实例必须包含创建委托的方法信息,传入的参数也必须符合方法入参信息。 + /// + /// 实例 + /// 入参 + /// 返回值 public async Task Invoke(object instance, object[] args) { object result = null; diff --git a/Library/Entity/ExplicitData.cs b/Library/Entity/ExplicitData.cs index 3b3a69c..ad486c3 100644 --- a/Library/Entity/ExplicitData.cs +++ b/Library/Entity/ExplicitData.cs @@ -7,12 +7,12 @@ namespace Serein.Library.Entity { /// - /// 参数 + /// 节点入参参数信息 /// public class ExplicitData { /// - /// 索引 + /// 参数索引 /// public int Index { get; set; } /// diff --git a/Library/Entity/MethodDetails.cs b/Library/Entity/MethodDetails.cs index da9cab6..d36aeef 100644 --- a/Library/Entity/MethodDetails.cs +++ b/Library/Entity/MethodDetails.cs @@ -23,67 +23,49 @@ namespace Serein.Library.Entity ActingInstance = ActingInstance, ActingInstanceType = ActingInstanceType, MethodDynamicType = MethodDynamicType, - // MethodGuid = Guid.NewGuid().ToString(), MethodTips = MethodTips, ReturnType = ReturnType, MethodName = MethodName, MethodLockName = MethodLockName, - IsNetFramework = IsNetFramework, IsProtectionParameter = IsProtectionParameter, ExplicitDatas = ExplicitDatas?.Select(it => it.Clone()).ToArray(), }; } - /// - /// 是否保护参数 + /// 是否保护参数(仅视觉效果参数,不影响运行实现) /// public bool IsProtectionParameter { get; set; } = false; /// - /// 作用实例的类型 + /// 作用实例的类型(多个相同的节点将拥有相同的类型) /// - public Type ActingInstanceType { get; set; } /// - /// 作用实例 + /// 作用实例(多个相同的节点将会共享同一个实例) /// - public object ActingInstance { get; set; } - /// - /// 方法GUID - /// - - // public string MethodGuid { get; set; } - /// /// 方法名称 /// - public string MethodName { get; set; } - /// - /// 方法委托 - /// - // public Delegate MethodDelegate { get; set; } - /// /// 节点类型 /// public NodeType MethodDynamicType { get; set; } - /// - /// 锁名称 - /// + /// + /// 锁名称(暂未实现) + /// public string MethodLockName { get; set; } /// /// 方法说明 /// - public string MethodTips { get; set; } @@ -99,91 +81,7 @@ namespace Serein.Library.Entity public Type ReturnType { get; set; } - public bool IsNetFramework { get; set; } - - - - - //public bool IsCanConnect(Type returnType) - //{ - // if (ExplicitDatas.Length == 0) - // { - // // 目标不需要传参,可以舍弃结果? - // return true; - // } - // var types = ExplicitDatas.Select(it => it.DataType).ToArray(); - // // 检查返回类型是否是元组类型 - // if (returnType.IsGenericType && IsValueTuple(returnType)) - // { - - // return CompareGenericArguments(returnType, types); - // } - // else - // { - // int index = 0; - // if (types[index] == typeof(DynamicContext)) - // { - // index++; - // if (types.Length == 1) - // { - // return true; - // } - // } - // // 被连接节点检查自己需要的参数类型,与发起连接的节点比较返回值类型 - // if (returnType == types[index]) - // { - // return true; - // } - // } - // return false; - //} - - ///// - ///// 检查元组类型 - ///// - ///// - ///// - //private bool IsValueTuple(Type type) - //{ - // if (!type.IsGenericType) return false; - - // var genericTypeDef = type.GetGenericTypeDefinition(); - // return genericTypeDef == typeof(ValueTuple<>) || - // genericTypeDef == typeof(ValueTuple<,>) || - // genericTypeDef == typeof(ValueTuple<,,>) || - // genericTypeDef == typeof(ValueTuple<,,,>) || - // genericTypeDef == typeof(ValueTuple<,,,,>) || - // genericTypeDef == typeof(ValueTuple<,,,,,>) || - // genericTypeDef == typeof(ValueTuple<,,,,,,>) || - // genericTypeDef == typeof(ValueTuple<,,,,,,,>); - //} - - //private bool CompareGenericArguments(Type returnType, Type[] parameterTypes) - //{ - // var genericArguments = returnType.GetGenericArguments(); - // var length = parameterTypes.Length; - - // for (int i = 0; i < genericArguments.Length; i++) - // { - // if (i >= length) return false; - - // if (IsValueTuple(genericArguments[i])) - // { - // // 如果当前参数也是 ValueTuple,递归检查嵌套的泛型参数 - // if (!CompareGenericArguments(genericArguments[i], parameterTypes.Skip(i).ToArray())) - // { - // return false; - // } - // } - // else if (genericArguments[i] != parameterTypes[i]) - // { - // return false; - // } - // } - - // return true; - //} } diff --git a/Library/Entity/NodeData.cs b/Library/Entity/NodeData.cs deleted file mode 100644 index e0ef99e..0000000 --- a/Library/Entity/NodeData.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Serein.Library.Entity -{ - public class NodeData - { - } -} diff --git a/Library/Entity/NodeDebugSetting.cs b/Library/Entity/NodeDebugSetting.cs index 0cd2163..fde7464 100644 --- a/Library/Entity/NodeDebugSetting.cs +++ b/Library/Entity/NodeDebugSetting.cs @@ -6,6 +6,9 @@ using static Serein.Library.Utils.ChannelFlowInterrupt; namespace Serein.Library.Entity { + /// + /// 节点调试设置,用于中断节点的运行 + /// public class NodeDebugSetting { /// @@ -13,32 +16,24 @@ namespace Serein.Library.Entity /// public bool IsEnable { get; set; } = true; - /// - /// 是否监视数据改变 - /// - // public bool IsMonitorFlowData { get; set; } = false; - /// /// 中断级别,暂时停止继续执行后继分支。 /// public InterruptClass InterruptClass { get; set; } = InterruptClass.None; - /// - /// 中断表达式 - /// - // public List InterruptExpressions { get; } = new List(); - /// /// 取消中断的回调函数 /// public Action CancelInterruptCallback { get; set; } /// - /// 中断Task + /// 中断Task(用来取消中断) /// public Func> GetInterruptTask { get; set; } } + + /// /// 中断级别,暂时停止继续执行后继分支。 /// diff --git a/Library/Entity/NodeLibrary.cs b/Library/Entity/NodeLibrary.cs index 439f6e9..0e042f4 100644 --- a/Library/Entity/NodeLibrary.cs +++ b/Library/Entity/NodeLibrary.cs @@ -5,9 +5,16 @@ using System.Text; namespace Serein.Library.Entity { + /// + /// 节点DLL依赖类,如果一个项目中引入了多个DLL,需要放置在同一个文件夹中 + /// public class NodeLibrary { + /// + /// 路径 + /// public string Path { get; set; } + public Assembly Assembly { get; set; } } diff --git a/Library/Entity/SereinProjectData.cs b/Library/Entity/SereinProjectData.cs index bc942f9..5ad4603 100644 --- a/Library/Entity/SereinProjectData.cs +++ b/Library/Entity/SereinProjectData.cs @@ -11,7 +11,7 @@ namespace Serein.Library.Entity { /// - /// 项目输出文件 + /// 项目保存文件 /// public class SereinProjectData { @@ -39,11 +39,6 @@ namespace Serein.Library.Entity public NodeInfo[] Nodes { get; set; } - ///// - ///// 区域集合 - ///// - - //public Region[] Regions { get; set; } } @@ -189,6 +184,9 @@ namespace Serein.Library.Entity public bool IsSelect { get; set; } } + /// + /// 显示参数 + /// public class Parameterdata { public bool State { get; set; } @@ -213,13 +211,5 @@ namespace Serein.Library.Entity } - /// - /// 区域 - /// - public class Region - { - public string guid { get; set; } - public NodeInfo[] ChildNodes { get; set; } - } } diff --git a/Library/Enums/ConnectionType.cs b/Library/Enums/ConnectionType.cs index e7706dc..e29df2a 100644 --- a/Library/Enums/ConnectionType.cs +++ b/Library/Enums/ConnectionType.cs @@ -4,10 +4,14 @@ using System.Text; namespace Serein.Library.Enums { + + /// + /// 表示了两个节点之间的连接关系,同时表示节点运行完成后,所会执行的下一个节点类型。 + /// public enum ConnectionType { /// - /// 默认属性 + /// 将不会继续执行 /// None, /// diff --git a/Library/Enums/FlipflopStateType.cs b/Library/Enums/FlipflopStateType.cs index 087c830..6565eec 100644 --- a/Library/Enums/FlipflopStateType.cs +++ b/Library/Enums/FlipflopStateType.cs @@ -6,7 +6,9 @@ using System.Threading.Tasks; namespace Serein.Library.Enums { - + /// + /// 触发器说明 + /// public enum FlipflopStateType { /// @@ -22,7 +24,7 @@ namespace Serein.Library.Enums /// Error, /// - /// 取消 + /// 取消(将不会执行触发器的后继节点) /// Cancel, } diff --git a/Library/Enums/NodeType.cs b/Library/Enums/NodeType.cs index a009330..f4dbe22 100644 --- a/Library/Enums/NodeType.cs +++ b/Library/Enums/NodeType.cs @@ -6,35 +6,67 @@ using System.Threading.Tasks; namespace Serein.Library.Enums { + /// + /// 用来判断该方法属于什么节点,使运行环境决定方法的运行逻辑 + /// public enum NodeType { /// /// 初始化,流程启动时执行(不生成节点) + /// 可以异步等待 /// Init, /// /// 开始载入,流程启动时执行(不生成节点) + /// 可以异步等待 /// Loading, /// /// 结束,流程结束时执行(不生成节点) + /// 可以异步等待 /// Exit, /// - /// 触发器(返回值必须为Task<IFlipflopContext<TResult>>) + /// 触发器节点,必须为标记在可异步等待的方法,建议与继承了 FlowTriggerk<TEnum> 的实例对象搭配使用 + /// 方法返回值必须为Task<IFlipflopContext<TResult>>,若为其它返回值,将不会创建节点。 + /// 触发器根据在分支中的位置,分为两种类型:流程分支中的触发器、全局触发器 + /// 一般的触发器:存在于分支某处,也可能是分支的终点,但一定不是流程的起点与分支的起点。 + /// 一般的触发器行为:在当前分支中执行一次之后不再执行,一般用于等待某个操作的响应。 + /// 一般的触发器入参:如果使用了 FlowTriggerk<TEnum> ,就会至少有一个枚举类型的参数,参数类型与 TEnum 泛型一致。 + /// 全局触发器:没有上游分支、同时并非流程的起始节点。 + /// 全局触发器行为:全局触发器会循环执行,直到流程结束。 + /// 一般的触发器入参:如果使用了 FlowTriggerk<TEnum> ,就会至少有一个枚举类型的参数,参数类型与 TEnum 泛型一致。 /// Flipflop, /// - /// 条件 - /// - Condition, - /// - /// 动作 + /// 动作节点,可以异步等待 + /// 如果不显式的设置入参数据(例如文本、@Get取值表达式),就会默认使用该节点的运行时上一个节点的数据。 + /// 假如上一节点是某个对象,但入参需要的是对象中某个属性/字段,则建议使用取值表达式、表达式节点获取所需要的数据。 + /// 关于@Get取值表达式的使用方法: + /// public class UserInfo + /// { + /// public string Name; // 取值表达式:@Get .Name + /// public string[] PhoneNums; // 获取第1项的取值表达式:@Get .PhoneNums[0] + /// } + /// 取值表达式可以符合直觉的如此获取实例成员:@Get .Data.Array[2].Data...... + /// 格式说明:@Get大小写不敏感,然后空一格,需要标记“.”,然后才是获取成员名称(成员名称大小写敏感)。 /// Action, } + + + class UserInfo + { + public string Name; + public int Id; + public string[] PhoneNums; + } + + + + /// /// 生成的节点控件 /// diff --git a/Library/Ex/FlipflopException.cs b/Library/Ex/FlipflopException.cs index 503021c..65d0add 100644 --- a/Library/Ex/FlipflopException.cs +++ b/Library/Ex/FlipflopException.cs @@ -4,23 +4,33 @@ using System.CodeDom; namespace Serein.Library.Ex { /// - /// 触发器 + /// 触发器异常 /// public class FlipflopException: Exception { public enum CancelClass { - // 取消当前分支的继续执行 + /// + /// 取消触发器当前所在分支的继续执行 + /// Branch, - // 取消整个触发器流程的再次执行 + /// + /// 取消整个触发器流程的再次执行(用于停止全局触发器) + /// Flow, } + /// + /// 是否已取消 + /// public bool IsCancel { get; } - public CancelClass Clsss { get; } + /// + /// 取消类型 + /// + public CancelClass Type { get; } public FlipflopException(string message, bool isCancel = true,CancelClass clsss = CancelClass.Branch) :base(message) { IsCancel = isCancel; - Clsss = clsss; + Type = clsss; } } } diff --git a/Library/Utils/ConvertHelper.cs b/Library/Utils/ConvertHelper.cs index c85cb10..e5b0184 100644 --- a/Library/Utils/ConvertHelper.cs +++ b/Library/Utils/ConvertHelper.cs @@ -7,6 +7,9 @@ using System.Threading.Tasks; namespace Serein.Library.Utils { + /// + /// 类型转换工具类 + /// public static class ConvertHelper { public static TResult ToConvert(this object data) diff --git a/Library/Utils/EmitHelper.cs b/Library/Utils/EmitHelper.cs index 46d495f..23e4782 100644 --- a/Library/Utils/EmitHelper.cs +++ b/Library/Utils/EmitHelper.cs @@ -8,12 +8,24 @@ using System.Threading.Tasks; namespace Serein.Library.Utils { + /// + /// Emit创建委托工具类 + /// public class EmitHelper { public enum EmitMethodType { + /// + /// 普通的方法。如果方法返回void时,将会返回null。 + /// Func, + /// + /// 无返回值的异步方法 + /// Task, + /// + /// 有返回值的异步方法 + /// HasResultTask, } public static bool IsGenericTask(Type returnType, out Type taskResult) @@ -38,11 +50,6 @@ namespace Serein.Library.Utils } } - //public static Delegate CreateDynamicMethod(MethodInfo methodInfo) - //{ - // return CreateDynamicMethod(methodInfo); - //} - public static EmitMethodType CreateDynamicMethod( MethodInfo methodInfo,out Delegate @delegate) { bool IsTask = IsGenericTask(methodInfo.ReturnType, out var taskGenericsType); diff --git a/Library/Utils/EnumHelper.cs b/Library/Utils/EnumHelper.cs index c8cae80..e7bb71b 100644 --- a/Library/Utils/EnumHelper.cs +++ b/Library/Utils/EnumHelper.cs @@ -6,11 +6,22 @@ using System.Text; namespace Serein.Library.Utils { + + /// + /// 枚举工具类,用于枚举转换器 + /// public static class EnumHelper { - public static bool TryConvertEnum(this string value, out T result) where T : struct, Enum + /// + /// 将字符串的字面量枚举值,转为对应的枚举值 + /// + /// 枚举 + /// 枚举字面量 + /// 返回的枚举值 + /// 是否转换成功 + public static bool TryConvertEnum(this string value, out TEnum result) where TEnum : struct, Enum { - if (!string.IsNullOrEmpty(value) && Enum.TryParse(value, true, out T tempResult) && Enum.IsDefined(typeof(T), tempResult)) + if (!string.IsNullOrEmpty(value) && Enum.TryParse(value, true, out TEnum tempResult) && Enum.IsDefined(typeof(TEnum), tempResult)) { result = tempResult; return true; @@ -18,6 +29,15 @@ namespace Serein.Library.Utils result = default; return false; } + + /// + /// 从枚举值的 BindValueAttribute 特性中 获取绑定的参数(用于绑定了某些内容的枚举值) + /// + /// 枚举类型 + /// 返回类型 + /// 枚举值 + /// 选择什么参数 + /// public static TResult GetBoundValue(TEnum enumValue, Func valueSelector) where TEnum : Enum { @@ -26,6 +46,7 @@ namespace Serein.Library.Utils return attribute != null ? (TResult)valueSelector(attribute) : default; } + public static object GetBoundValue(Type enumType,object enumValue, Func valueSelector) { var fieldInfo = enumType.GetField(enumValue.ToString()); @@ -34,6 +55,16 @@ namespace Serein.Library.Utils return attribute != null ? valueSelector(attribute) : default; } + + /// + /// 从枚举值从获取自定义特性的成员,并自动转换类型 + /// + /// 枚举类型 + /// 自定义特性类型 + /// 返回类型 + /// 枚举值 + /// 特性成员选择 + /// public static TResult GetBoundValue(TEnum enumValue, Func valueSelector) where TEnum : Enum diff --git a/Library/Utils/ExpressionHelper.cs b/Library/Utils/ExpressionHelper.cs index 02c2615..b454697 100644 --- a/Library/Utils/ExpressionHelper.cs +++ b/Library/Utils/ExpressionHelper.cs @@ -10,7 +10,7 @@ using System.Threading.Tasks; namespace Serein.Library.Utils { /// - /// 基于类型创建表达式树反射委托 + /// 基于类型创建表达式树反射委托(目前已使用EmitHelper代替) /// public static class ExpressionHelper { diff --git a/Library/Utils/SereinIoc.cs b/Library/Utils/SereinIoc.cs index 8ca5fb7..d777ea5 100644 --- a/Library/Utils/SereinIoc.cs +++ b/Library/Utils/SereinIoc.cs @@ -117,20 +117,21 @@ namespace Serein.Library.Utils /// /// /// - public void CustomRegisterInstance(string key, object instance, bool needInjectProperty = true) + public bool CustomRegisterInstance(string key, object instance, bool needInjectProperty = true) { // 不存在时才允许创建 - if (!_dependencies.ContainsKey(key)) + if (_dependencies.ContainsKey(key)) { - _dependencies.TryAdd(key, instance); + return false; } - + _dependencies.TryAdd(key, instance); if (needInjectProperty) { InjectDependencies(instance); // 注入实例需要的依赖项 } InjectUnfinishedDependencies(key, instance); // 检查是否存在其它实例需要该类型 OnIOCMembersChanged?.Invoke(new IOCMembersChangedEventArgs(key, instance)); + return true; } public object Get(Type type) { diff --git a/Net462DllTest/LogicControl/PlcLogicControl.cs b/Net462DllTest/LogicControl/PlcLogicControl.cs index d985a72..bba2645 100644 --- a/Net462DllTest/LogicControl/PlcLogicControl.cs +++ b/Net462DllTest/LogicControl/PlcLogicControl.cs @@ -51,15 +51,13 @@ namespace Net462DllTest.LogicControl #region 触发器节点 [NodeAction(NodeType.Flipflop, "等待变量更新")] - public async Task> WaitTask(PlcVarName varName = PlcVarName.ErrorCode) + public async Task> WaitTask(PlcVarName varName = PlcVarName.ErrorCode) { - try { - var triggerData = await MyPlc.CreateTaskAsync(varName); - + var triggerData = await MyPlc.CreateTaskAsync(varName); await Console.Out.WriteLineAsync($"PLC变量触发器[{varName}]传递数据:{triggerData}"); - return new FlipflopContext(FlipflopStateType.Succeed, triggerData); + return new FlipflopContext(FlipflopStateType.Succeed, triggerData); } catch (Exception) { diff --git a/Net462DllTest/LogicControl/ViewLogicControl.cs b/Net462DllTest/LogicControl/ViewLogicControl.cs index 50d1844..d3ffd6d 100644 --- a/Net462DllTest/LogicControl/ViewLogicControl.cs +++ b/Net462DllTest/LogicControl/ViewLogicControl.cs @@ -51,18 +51,7 @@ namespace Net462DllTest.LogicControl } #endregion - //[NodeAction(NodeType.Action, "打开窗体(指定枚举值)")] - //public void OpenForm(IDynamicContext context, - // FromValue fromId = FromValue.FromWorkBenchView, - // bool isTop = true) - //{ - // var fromType = EnumHelper.GetBoundValue(fromId, attr => attr.Value); - // if (fromType is null) return; - // if (context.Env.IOC.Instantiate(fromType) is Form form) - // { - // ViewManagement.OpenView(form, isTop); - // } - //} + [NodeAction(NodeType.Action, "打开窗体(转换器)")] public void OpenForm2([EnumTypeConvertor(typeof(FromValue))] Form form, bool isTop = true) diff --git a/Net462DllTest/Web/FlowController.cs b/Net462DllTest/Web/FlowController.cs index 6035c99..3208ab4 100644 --- a/Net462DllTest/Web/FlowController.cs +++ b/Net462DllTest/Web/FlowController.cs @@ -39,7 +39,7 @@ namespace Net462DllTest.Web [WebApi(ApiType.POST)] public dynamic PlcOp([Url] string var, int value) { - if (EnumHelper.TryConvertEnum(var,out var signal)) + if (EnumHelper.TryConvertEnum(var, out var signal)) { Console.WriteLine($"外部触发 {signal} 信号,信号内容 : {value} "); plcDevice.Trigger(signal, value);// 通过 Web Api 模拟外部输入信号 diff --git a/NodeFlow/FlowEnvironment.cs b/NodeFlow/FlowEnvironment.cs index 40734cb..c994551 100644 --- a/NodeFlow/FlowEnvironment.cs +++ b/NodeFlow/FlowEnvironment.cs @@ -1249,11 +1249,11 @@ namespace Serein.NodeFlow { return sereinIOC.Get(key); } - - void ISereinIOC.CustomRegisterInstance(string key, object instance, bool needInjectProperty) + + bool ISereinIOC.CustomRegisterInstance(string key, object instance, bool needInjectProperty) { - sereinIOC.CustomRegisterInstance(key, instance, needInjectProperty); + return sereinIOC.CustomRegisterInstance(key, instance, needInjectProperty); } object ISereinIOC.Instantiate(Type type) diff --git a/NodeFlow/FlowStarter.cs b/NodeFlow/FlowStarter.cs index 9c6127a..9a72f1b 100644 --- a/NodeFlow/FlowStarter.cs +++ b/NodeFlow/FlowStarter.cs @@ -415,7 +415,7 @@ namespace Serein.NodeFlow catch(FlipflopException ex) { await Console.Out.WriteLineAsync($"触发器[{singleFlipFlopNode.MethodDetails.MethodName}]因非预期异常终止。"+ex.Message); - if (ex.Clsss == FlipflopException.CancelClass.Flow) + if (ex.Type == FlipflopException.CancelClass.Flow) { break; } diff --git a/NodeFlow/Model/SingleFlipflopNode.cs b/NodeFlow/Model/SingleFlipflopNode.cs index 856e08c..753c81f 100644 --- a/NodeFlow/Model/SingleFlipflopNode.cs +++ b/NodeFlow/Model/SingleFlipflopNode.cs @@ -55,7 +55,7 @@ namespace Serein.NodeFlow.Model } catch (FlipflopException ex) { - if(ex.Clsss == FlipflopException.CancelClass.Flow) + if(ex.Type == FlipflopException.CancelClass.Flow) { throw; }