diff --git a/Library.Core/NodeFlow/FlipflopContext.cs b/Library.Core/NodeFlow/FlipflopContext.cs index 3819260..8dd9884 100644 --- a/Library.Core/NodeFlow/FlipflopContext.cs +++ b/Library.Core/NodeFlow/FlipflopContext.cs @@ -65,15 +65,15 @@ namespace Serein.Library.Core.NodeFlow /// public class FlipflopContext : IFlipflopContext { - public FlowStateType State { get; set; } + public FlipflopStateType State { get; set; } public object Data { get; set; } - public FlipflopContext(FlowStateType ffState) + public FlipflopContext(FlipflopStateType ffState) { State = ffState; } - public FlipflopContext(FlowStateType ffState, object data) + public FlipflopContext(FlipflopStateType ffState, object data) { State = ffState; Data = data; diff --git a/Library.Framework/NodeFlow/DynamicContext.cs b/Library.Framework/NodeFlow/DynamicContext.cs index 1335ee5..6107d70 100644 --- a/Library.Framework/NodeFlow/DynamicContext.cs +++ b/Library.Framework/NodeFlow/DynamicContext.cs @@ -17,7 +17,6 @@ namespace Serein.Library.Framework.NodeFlow SereinIoc = sereinIoc; FlowEnvironment = flowEnvironment; } - public NodeRunCts NodeRunCts { get; set; } public ISereinIoc SereinIoc { get; } public IFlowEnvironment FlowEnvironment { get; } diff --git a/Library.Framework/NodeFlow/FlipflopContext.cs b/Library.Framework/NodeFlow/FlipflopContext.cs index f97056b..5557d63 100644 --- a/Library.Framework/NodeFlow/FlipflopContext.cs +++ b/Library.Framework/NodeFlow/FlipflopContext.cs @@ -5,24 +5,6 @@ using System.Threading.Tasks; namespace Serein.Library.Framework.NodeFlow { - //public enum FfState - //{ - // Succeed, - // Cancel, - // Error, - //} - - //public class FlipflopContext - //{ - // public FlowStateType State { get; set; } - // public object? Data { get; set; } - // public FlipflopContext(FlowStateType ffState, object? data = null) - // { - // State = ffState; - // Data = data; - // } - //} - public static class FlipflopFunc { /// @@ -75,20 +57,19 @@ namespace Serein.Library.Framework.NodeFlow /// public class FlipflopContext : IFlipflopContext { - public FlowStateType State { get; set; } + public FlipflopStateType State { get; set; } //public TResult? Data { get; set; } public object Data { get; set; } - public FlipflopContext(FlowStateType ffState) + public FlipflopContext(FlipflopStateType ffState) { State = ffState; } - public FlipflopContext(FlowStateType ffState, object data) + public FlipflopContext(FlipflopStateType ffState, object data) { State = ffState; Data = data; } - - } + } diff --git a/Library.Framework/Serein.Library.Framework.csproj b/Library.Framework/Serein.Library.Framework.csproj index f0f00c1..3a690f9 100644 --- a/Library.Framework/Serein.Library.Framework.csproj +++ b/Library.Framework/Serein.Library.Framework.csproj @@ -55,7 +55,7 @@ - {5e19d0f2-913a-4d1c-a6f8-1e1227baa0e3} + {55C77D23-2FD3-43D1-918C-DC3DE9614F0F} Serein.Library diff --git a/Library/Api/IFlipflopContext.cs b/Library/Api/IFlipflopContext.cs index 8722869..5f6b8a8 100644 --- a/Library/Api/IFlipflopContext.cs +++ b/Library/Api/IFlipflopContext.cs @@ -4,7 +4,7 @@ namespace Serein.Library.Api { public interface IFlipflopContext { - FlowStateType State { get; set; } + FlipflopStateType State { get; set; } object Data { get; set; } } } diff --git a/Library/Enums/ConnectionType.cs b/Library/Enums/ConnectionType.cs index 8c40635..7a90ea3 100644 --- a/Library/Enums/ConnectionType.cs +++ b/Library/Enums/ConnectionType.cs @@ -6,6 +6,10 @@ namespace Serein.Library.Enums { public enum ConnectionType { + /// + /// 不执行分支 + /// + None, /// /// 真分支 /// diff --git a/Library/Enums/FlowStateType.cs b/Library/Enums/FlipflopStateType.cs similarity index 89% rename from Library/Enums/FlowStateType.cs rename to Library/Enums/FlipflopStateType.cs index f142e27..087c830 100644 --- a/Library/Enums/FlowStateType.cs +++ b/Library/Enums/FlipflopStateType.cs @@ -7,12 +7,8 @@ using System.Threading.Tasks; namespace Serein.Library.Enums { - public enum FlowStateType + public enum FlipflopStateType { - /// - /// 待执行 - /// - None, /// /// 成功(方法成功执行) /// @@ -25,5 +21,11 @@ namespace Serein.Library.Enums /// 异常(节点没有成功执行,执行时发生非预期的错误) /// Error, + /// + /// 取消 + /// + Cancel, } + + } diff --git a/Library/Ex/FlipflopException.cs b/Library/Ex/FlipflopException.cs new file mode 100644 index 0000000..d562da4 --- /dev/null +++ b/Library/Ex/FlipflopException.cs @@ -0,0 +1,16 @@ +using System; + +namespace Serein.Library.Ex +{ + /// + /// 触发器 + /// + public class FlipflopException: Exception + { + public bool IsCancel { get; } + public FlipflopException(string message, bool isCancel = true) :base(message) + { + IsCancel = isCancel; + } + } +} diff --git a/Library/NodeAttribute.cs b/Library/NodeAttribute.cs index a0aab98..0036922 100644 --- a/Library/NodeAttribute.cs +++ b/Library/NodeAttribute.cs @@ -27,7 +27,7 @@ namespace Serein.Library.Attributes /// - /// 标记一个方法是什么类型,加载dll后用来拖拽到画布中 + /// 建议触发器手动设置返回类型 /// [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class NodeActionAttribute : Attribute @@ -45,9 +45,6 @@ namespace Serein.Library.Attributes public bool Scan; public string MethodTips; public NodeType MethodDynamicType; - /// - /// 推荐触发器手动设置返回类型 - /// public Type ReturnType; public string LockName; } diff --git a/Library/Utils/TcsSignal.cs b/Library/Utils/TcsSignalFlipflop.cs similarity index 87% rename from Library/Utils/TcsSignal.cs rename to Library/Utils/TcsSignalFlipflop.cs index 6355acc..fa98d9d 100644 --- a/Library/Utils/TcsSignal.cs +++ b/Library/Utils/TcsSignalFlipflop.cs @@ -1,6 +1,7 @@ -using System; -using System.Threading.Tasks; +using Serein.Library.Ex; +using System; using System.Collections.Concurrent; +using System.Threading.Tasks; namespace Serein.Library.Core.NodeFlow.Tool { @@ -13,9 +14,8 @@ namespace Serein.Library.Core.NodeFlow.Tool // } //} - public class TcsSignal where TSignal : struct, Enum + public class TcsSignalFlipflop where TSignal : struct, Enum { - //public ConcurrentDictionary>> TcsEvent { get; } = new(); public ConcurrentDictionary> TcsEvent { get; } = new ConcurrentDictionary>(); public ConcurrentDictionary TcsLock { get; } = new ConcurrentDictionary(); @@ -56,7 +56,7 @@ namespace Serein.Library.Core.NodeFlow.Tool { foreach (var tcs in TcsEvent.Values) { - tcs.SetException(new Exception("任务取消")); + tcs.SetException(new FlipflopException("任务取消")); } TcsEvent.Clear(); } diff --git a/NodeFlow/Base/NodeModelBaseData.cs b/NodeFlow/Base/NodeModelBaseData.cs index 6b3aab1..c4e9db5 100644 --- a/NodeFlow/Base/NodeModelBaseData.cs +++ b/NodeFlow/Base/NodeModelBaseData.cs @@ -1,10 +1,6 @@ -using Newtonsoft.Json; -using Serein.Library.Api; +using Serein.Library.Api; using Serein.Library.Entity; using Serein.Library.Enums; -using Serein.NodeFlow.Model; -using Serein.NodeFlow.Tool.SerinExpression; -using System.Xml.Linq; namespace Serein.NodeFlow.Base { @@ -65,12 +61,14 @@ namespace Serein.NodeFlow.Base /// /// 不同分支的子节点 /// - public Dictionary> SuccessorNodes { get; } + public Dictionary> SuccessorNodes { get; } + + public ConnectionType NextOrientation { get; set; } = ConnectionType.None; /// /// 当前执行状态(进入真分支还是假分支,异常分支在异常中确定) /// - public FlowStateType FlowState { get; set; } = FlowStateType.None; + // public FlowStateType FlowState { get; set; } = FlowStateType.Cancel; /// /// 运行时的异常信息(仅在 FlowState 为 Error 时存在对应值) diff --git a/NodeFlow/Base/NodeModelBaseFunc.cs b/NodeFlow/Base/NodeModelBaseFunc.cs index 0a3bb54..c678ad0 100644 --- a/NodeFlow/Base/NodeModelBaseFunc.cs +++ b/NodeFlow/Base/NodeModelBaseFunc.cs @@ -2,6 +2,7 @@ using Serein.Library.Api; using Serein.Library.Entity; using Serein.Library.Enums; +using Serein.Library.Ex; using Serein.NodeFlow.Tool.SerinExpression; using System; using System.Collections.Generic; @@ -92,14 +93,13 @@ namespace Serein.NodeFlow.Base currentNode.FlowData = currentNode.Execute(context); } - ConnectionType connection = currentNode.FlowState switch + if(currentNode.NextOrientation == ConnectionType.None) { - FlowStateType.Succeed => ConnectionType.IsSucceed, - FlowStateType.Fail => ConnectionType.IsFail, - FlowStateType.Error => ConnectionType.IsError, - _ => throw new Exception("非预期的枚举值") - }; - var nextNodes = currentNode.SuccessorNodes[connection]; + // 不再执行 + break; + } + + var nextNodes = currentNode.SuccessorNodes[currentNode.NextOrientation]; // 将下一个节点集合中的所有节点逆序推入栈中 for (int i = nextNodes.Count - 1; i >= 0; i--) @@ -148,12 +148,12 @@ namespace Serein.NodeFlow.Base result = func?.Invoke(md.ActingInstance, parameters); } } - FlowState = FlowStateType.Succeed; + NextOrientation = ConnectionType.IsSucceed; return result; } catch (Exception ex) { - FlowState = FlowStateType.Error; + NextOrientation = ConnectionType.IsError; RuningException = ex; } @@ -184,23 +184,16 @@ namespace Serein.NodeFlow.Base object?[]? parameters = GetParameters(context, MethodDetails); flipflopContext = await ((Func>)md.MethodDelegate).Invoke(MethodDetails.ActingInstance, parameters); } - - if (flipflopContext != null) + if (flipflopContext == null) { - FlowState = flipflopContext.State; - if (flipflopContext.State == FlowStateType.Succeed) - { - result = flipflopContext.Data; - } - else - { - result = null; - } + throw new FlipflopException("没有返回上下文"); } + NextOrientation = flipflopContext.State.ToContentType(); + result = flipflopContext.Data; } catch (Exception ex) { - FlowState = FlowStateType.Error; + NextOrientation = ConnectionType.IsError; RuningException = ex; } diff --git a/NodeFlow/FlowEnvironment.cs b/NodeFlow/FlowEnvironment.cs index c831cce..b3a030b 100644 --- a/NodeFlow/FlowEnvironment.cs +++ b/NodeFlow/FlowEnvironment.cs @@ -7,6 +7,7 @@ using Serein.NodeFlow.Base; using Serein.NodeFlow.Model; using Serein.NodeFlow.Tool; using System.Diagnostics; +using System.Net.Mime; using System.Reflection; using System.Reflection.Emit; using System.Xml.Linq; @@ -618,6 +619,18 @@ namespace Serein.NodeFlow Path = assembly.Location, }; } + + public static ConnectionType ToContentType(this FlipflopStateType flowStateType) + { + return flowStateType switch + { + FlipflopStateType.Succeed => ConnectionType.IsSucceed, + FlipflopStateType.Fail => ConnectionType.IsFail, + FlipflopStateType.Error => ConnectionType.IsError, + FlipflopStateType.Cancel => ConnectionType.None, + _ => throw new NotImplementedException("未定义的流程状态") + }; + } } diff --git a/NodeFlow/FlowStarter.cs b/NodeFlow/FlowStarter.cs index 64a6805..15815c1 100644 --- a/NodeFlow/FlowStarter.cs +++ b/NodeFlow/FlowStarter.cs @@ -159,11 +159,14 @@ namespace Serein.NodeFlow IFlipflopContext flipflopContext = await func.Invoke(md.ActingInstance, parameters); - if (flipflopContext.State == FlowStateType.Succeed) + ConnectionType connection = flipflopContext.State.ToContentType(); + + if (connection != ConnectionType.None) { - singleFlipFlopNode.FlowState = FlowStateType.Succeed; + singleFlipFlopNode.NextOrientation = connection; singleFlipFlopNode.FlowData = flipflopContext.Data; - var tasks = singleFlipFlopNode.SuccessorNodes[ConnectionType.IsSucceed].Select(nextNode => + + var tasks = singleFlipFlopNode.SuccessorNodes[connection].Select(nextNode => { var context = new DynamicContext(SereinIoc,flowEnvironment); nextNode.PreviousNode = singleFlipFlopNode; diff --git a/NodeFlow/Model/CompositeConditionNode.cs b/NodeFlow/Model/CompositeConditionNode.cs index ff937ae..6d5b932 100644 --- a/NodeFlow/Model/CompositeConditionNode.cs +++ b/NodeFlow/Model/CompositeConditionNode.cs @@ -26,50 +26,38 @@ namespace Serein.NodeFlow.Model /// public override object? Execute(IDynamicContext context) { - // bool allTrue = ConditionNodes.All(condition => Judge(context,condition.MethodDetails)); - // bool IsAllTrue = true; // 初始化为 true - FlowState = FlowStateType.Succeed; + // NextOrientation = ConnectionType.IsSucceed; + + // 条件区域中遍历每个条件节点 foreach (SingleConditionNode? node in ConditionNodes) { var state = Judge(context, node); - if (state == FlowStateType.Fail || FlowStateType.Fail == FlowStateType.Error) + NextOrientation = state; // 每次判读完成后,设置区域后继方向为判断结果 + if (state != ConnectionType.IsSucceed) { - FlowState = state; - break;// 一旦发现条件为假,立即退出循环 + // 如果条件不通过,立刻推出循环 + break; } } - + return PreviousNode?.FlowData; - //if (IsAllTrue) - //{ - // foreach (var nextNode in TrueBranchNextNodes) - // { - // nextNode.ExecuteStack(context); - // } - //} - //else - //{ - // foreach (var nextNode in FalseBranchNextNodes) - // { - // nextNode.ExecuteStack(context); - // } - //} + } - - - private FlowStateType Judge(IDynamicContext context, SingleConditionNode node) + private ConnectionType Judge(IDynamicContext context, SingleConditionNode node) { try { node.Execute(context); - return node.FlowState; + return node.NextOrientation; } catch (Exception ex) { Console.WriteLine(ex.Message); - return FlowStateType.Error; + NextOrientation = ConnectionType.IsError; + RuningException = ex; + return ConnectionType.IsError; } } diff --git a/NodeFlow/Model/SingleConditionNode.cs b/NodeFlow/Model/SingleConditionNode.cs index 04c5d11..cba95de 100644 --- a/NodeFlow/Model/SingleConditionNode.cs +++ b/NodeFlow/Model/SingleConditionNode.cs @@ -43,15 +43,15 @@ namespace Serein.NodeFlow.Model try { var isPass = SerinConditionParser.To(result, Expression); - FlowState = isPass ? FlowStateType.Succeed : FlowStateType.Fail; + NextOrientation = isPass ? ConnectionType.IsSucceed : ConnectionType.IsFail; } catch (Exception ex) { - FlowState = FlowStateType.Error; + NextOrientation = ConnectionType.IsError; RuningException = ex; } - Console.WriteLine($"{result} {Expression} -> " + FlowState); + Console.WriteLine($"{result} {Expression} -> " + NextOrientation); return result; } diff --git a/NodeFlow/Model/SingleExpOpNode.cs b/NodeFlow/Model/SingleExpOpNode.cs index 72193cd..7953401 100644 --- a/NodeFlow/Model/SingleExpOpNode.cs +++ b/NodeFlow/Model/SingleExpOpNode.cs @@ -3,6 +3,7 @@ using Serein.Library.Entity; using Serein.Library.Enums; using Serein.NodeFlow.Base; using Serein.NodeFlow.Tool.SerinExpression; +using System.Text; namespace Serein.NodeFlow.Model { @@ -21,16 +22,27 @@ namespace Serein.NodeFlow.Model { var data = PreviousNode?.FlowData; - var newData = SerinExpressionEvaluator.Evaluate(Expression, data, out bool isChange); + try + { + var newData = SerinExpressionEvaluator.Evaluate(Expression, data, out bool isChange); + Console.WriteLine(newData); + object? result = null; + if (isChange) + { + result = newData; + } + else + { + result = PreviousNode?.FlowData; + } - FlowState = FlowStateType.Succeed; - Console.WriteLine(newData); - if (isChange) - { - return newData; + NextOrientation = ConnectionType.IsSucceed; + return result; } - else + catch (Exception ex) { + NextOrientation = ConnectionType.IsError; + RuningException = ex; return PreviousNode?.FlowData; } diff --git a/NodeFlow/Model/SingleFlipflopNode.cs b/NodeFlow/Model/SingleFlipflopNode.cs index 4b58ca5..9c2eef5 100644 --- a/NodeFlow/Model/SingleFlipflopNode.cs +++ b/NodeFlow/Model/SingleFlipflopNode.cs @@ -1,5 +1,6 @@ using Serein.Library.Api; using Serein.Library.Entity; +using Serein.Library.Ex; using Serein.NodeFlow.Base; namespace Serein.NodeFlow.Model @@ -7,9 +8,11 @@ namespace Serein.NodeFlow.Model public class SingleFlipflopNode : NodeModelBase { - public override object Execute(IDynamicContext context) + public override object? Execute(IDynamicContext context) { - throw new NotImplementedException("无法以非await/async的形式调用触发器"); + NextOrientation = Library.Enums.ConnectionType.IsError; + RuningException = new FlipflopException ("无法以非await/async的形式调用触发器"); + return null; } public override Parameterdata[] GetParameterdatas() diff --git a/NodeFlow/Tool/MethodDetailsHelper.cs b/NodeFlow/Tool/MethodDetailsHelper.cs index 5f59431..1c33a04 100644 --- a/NodeFlow/Tool/MethodDetailsHelper.cs +++ b/NodeFlow/Tool/MethodDetailsHelper.cs @@ -67,6 +67,10 @@ public static class MethodDetailsHelperTmp var methodName = method.Name; var attribute = method.GetCustomAttribute(); + if(attribute is null) + { + return null; + } var explicitDataOfParameters = GetExplicitDataOfParameters(method.GetParameters()); // 生成委托 var methodDelegate = GenerateMethodDelegate(type, // 方法所在的对象类型 @@ -74,6 +78,16 @@ public static class MethodDetailsHelperTmp method.GetParameters(),// 方法参数 method.ReturnType);// 返回值 + Type returnType; + if (attribute?.MethodDynamicType == Library.Enums.NodeType.Flipflop) + { + // 触发器节点 + returnType = attribute.ReturnType; + } + else + { + returnType = method.ReturnType; + } var dllTypeName = $"{assemblyName}.{type.Name}"; // object instance = Activator.CreateInstance(type); @@ -89,7 +103,7 @@ public static class MethodDetailsHelperTmp MethodLockName = attribute.LockName, MethodTips = attribute.MethodTips, ExplicitDatas = explicitDataOfParameters, - ReturnType = method.ReturnType, + ReturnType = returnType, }; } diff --git a/README.md b/README.md index 4ba4c2e..80bc230 100644 --- a/README.md +++ b/README.md @@ -3,10 +3,11 @@ 不定期在Bilibili个人空间上更新相关的视频。 https://space.bilibili.com/33526379 -# 当前任务 2024年9月12日22:32:10 -1. 将运行环境从UI(WPF)中独立出来,方便控制台程序直接运行项目文件。 -2. 包装数据类型, 优化传递效率(尽可能避免拆箱、装箱) -3. 优化触发器节点(显示传出类型) +# 当前任务 2024年9月15日22:04:40 +* 计划新增基础节点“属性包装器”,用来收集各个节点的数据,包装成匿名对象/Json类型 +* 计划编写网络方面的通讯,方便传出、传入数据 +* 包装数据类型, 优化传递效率(尽可能避免拆箱、装箱) + # 如何加载我的DLL? 使用 **DynamicFlow** 特性标记你的类,可以参照 **MyDll** 与 **SereinWAT** 的实现。编译为 Dll文件 后,拖入到软件中即可。 diff --git a/WorkBench/Node/View/FlipflopNodeControl.xaml b/WorkBench/Node/View/FlipflopNodeControl.xaml index c400edb..2c56308 100644 --- a/WorkBench/Node/View/FlipflopNodeControl.xaml +++ b/WorkBench/Node/View/FlipflopNodeControl.xaml @@ -28,6 +28,18 @@ + + + + + + + + + + + +