From aa3d1763edf1a45de852151f3d7dd188d92af7e0 Mon Sep 17 00:00:00 2001 From: fengjiayi <12821976+ning_xi@user.noreply.gitee.com> Date: Tue, 8 Jul 2025 17:37:03 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BA=86=E8=8A=82=E7=82=B9?= =?UTF-8?q?=E5=8A=A0=E8=BD=BD=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Library/Enums/ConnectionInvokeType.cs | 10 +- Library/Extension/FlowModelExtension.cs | 19 ++- .../FlowNode/LightweightFlowEnvironment.cs | 63 +++++-- Library/FlowNode/SereinProjectData.cs | 12 +- Library/Utils/BenchmarkHelpers.cs | 3 +- NodeFlow/Env/FlowEdit.cs | 85 ++++++++-- NodeFlow/Services/FlowCoreGenerateService.cs | 160 +++++++++++------- .../Converters/BoolToVisibilityConverter.cs | 2 +- 8 files changed, 260 insertions(+), 94 deletions(-) diff --git a/Library/Enums/ConnectionInvokeType.cs b/Library/Enums/ConnectionInvokeType.cs index 9164d57..ef91b69 100644 --- a/Library/Enums/ConnectionInvokeType.cs +++ b/Library/Enums/ConnectionInvokeType.cs @@ -13,23 +13,23 @@ namespace Serein.Library /// /// 将不会继续执行 /// - None, + None = -1, /// /// 上游分支(执行当前节点前会执行一次上游分支),默认执行。 /// - Upstream, + Upstream = 0, /// /// 真分支(表示当前节点顺利完成) /// - IsSucceed, + IsSucceed = 1, /// /// 假分支(一般用于条件控件,条件为假时才会触发该类型的分支) /// - IsFail, + IsFail = 2, /// /// 异常发生分支(当前节点对应的方法执行时出现非预期的异常) /// - IsError, + IsError = 3, } diff --git a/Library/Extension/FlowModelExtension.cs b/Library/Extension/FlowModelExtension.cs index a3890c9..5b02b24 100644 --- a/Library/Extension/FlowModelExtension.cs +++ b/Library/Extension/FlowModelExtension.cs @@ -96,12 +96,17 @@ namespace Serein.Library public static NodeInfo ToInfo(this IFlowNode nodeModel) { // if (MethodDetails == null) return null; - var trueNodes = nodeModel.SuccessorNodes[ConnectionInvokeType.IsSucceed].Select(item => item.Guid); // 真分支 + /*var trueNodes = nodeModel.SuccessorNodes[ConnectionInvokeType.IsSucceed].Select(item => item.Guid); // 真分支 var falseNodes = nodeModel.SuccessorNodes[ConnectionInvokeType.IsFail].Select(item => item.Guid);// 假分支 var errorNodes = nodeModel.SuccessorNodes[ConnectionInvokeType.IsError].Select(item => item.Guid);// 异常分支 - var upstreamNodes = nodeModel.SuccessorNodes[ConnectionInvokeType.Upstream].Select(item => item.Guid);// 上游分支 + var upstreamNodes = nodeModel.SuccessorNodes[ConnectionInvokeType.Upstream].Select(item => item.Guid);// 上游分支*/ + + var successorNodes = nodeModel.SuccessorNodes.ToDictionary(kv => kv.Key, kv => kv.Value.Select(item => item.Guid).ToArray()); // 后继分支 + var previousNodes = nodeModel.PreviousNodes.ToDictionary(kv => kv.Key, kv => kv.Value.Select(item => item.Guid).ToArray()); // 后继分支 + + // 生成参数列表 - ParameterData[] parameterData = nodeModel.SaveParameterInfo(); + ParameterData[] parameterDatas = nodeModel.SaveParameterInfo(); var nodeInfo = new NodeInfo { @@ -112,17 +117,19 @@ namespace Serein.Library MethodName = nodeModel.MethodDetails?.MethodName, Label = nodeModel.MethodDetails?.MethodAnotherName, Type = nodeModel.ControlType.ToString(), //this.GetType().ToString(), - TrueNodes = trueNodes.ToArray(), + /*TrueNodes = trueNodes.ToArray(), FalseNodes = falseNodes.ToArray(), UpstreamNodes = upstreamNodes.ToArray(), - ParameterData = parameterData.ToArray(), - ErrorNodes = errorNodes.ToArray(), + ErrorNodes = errorNodes.ToArray(),*/ + ParameterData = parameterDatas, Position = nodeModel.Position, IsProtectionParameter = nodeModel.DebugSetting.IsProtectionParameter, IsInterrupt = nodeModel.DebugSetting.IsInterrupt, IsEnable = nodeModel.DebugSetting.IsEnable, ParentNodeGuid = nodeModel.ContainerNode?.Guid, ChildNodeGuids = nodeModel.ChildrenNode.Select(item => item.Guid).ToArray(), + SuccessorNodes = successorNodes, + PreviousNodes = previousNodes, }; nodeInfo.Position.X = Math.Round(nodeInfo.Position.X, 1); nodeInfo.Position.Y = Math.Round(nodeInfo.Position.Y, 1); diff --git a/Library/FlowNode/LightweightFlowEnvironment.cs b/Library/FlowNode/LightweightFlowEnvironment.cs index 95557e5..40644f7 100644 --- a/Library/FlowNode/LightweightFlowEnvironment.cs +++ b/Library/FlowNode/LightweightFlowEnvironment.cs @@ -148,11 +148,11 @@ namespace Serein.Library private void Init() { - PreviousNodes = new Dictionary>(); + //PreviousNodes = new Dictionary>(); SuccessorNodes = new Dictionary>(); foreach (ConnectionInvokeType ctType in NodeStaticConfig.ConnectionTypes) { - PreviousNodes[ctType] = new List(); + //PreviousNodes[ctType] = new List(); SuccessorNodes[ctType] = new List(); } } @@ -175,23 +175,48 @@ namespace Serein.Library /// /// 不同分支的父节点(流程调用) /// - public Dictionary> PreviousNodes { get; private set; } + //public Dictionary> PreviousNodes { get; private set; } /// /// 不同分支的子节点(流程调用) /// - public Dictionary> SuccessorNodes { get; private set; } + public Dictionary> SuccessorNodes { get; private set; } + public CallNode[][] ChildNodes { get; private set; } = new CallNode[][] + { + new CallNode[32], + new CallNode[32], + new CallNode[32], + new CallNode[32] + }; + public int GetCount(ConnectionInvokeType type) + { + if (type == ConnectionInvokeType.Upstream) return UpstreamNodeCount; + if (type == ConnectionInvokeType.IsSucceed) return IsSuccessorNodeCount; + if (type == ConnectionInvokeType.IsFail) return IsFailNodeCount; + if (type == ConnectionInvokeType.IsError) return IsErrorNodeCount; + return 0; + } + + public int UpstreamNodeCount { get; private set; } = 0; + public int IsSuccessorNodeCount { get; private set; } = 0; + public int IsFailNodeCount { get; private set; } = 0; + public int IsErrorNodeCount { get; private set; } = 0; public CallNode AddChildNodeUpstream(CallNode callNode) { var connectionInvokeType = ConnectionInvokeType.Upstream; + ChildNodes[(int)connectionInvokeType][UpstreamNodeCount++] = callNode; SuccessorNodes[connectionInvokeType].Add(callNode); return this; } + public CallNode AddChildNodeSucceed(CallNode callNode) { - var connectionInvokeType = ConnectionInvokeType.IsSucceed; + ChildNodes[0][UpstreamNodeCount++] = callNode; + + var connectionInvokeType = ConnectionInvokeType.IsSucceed; + ChildNodes[(int)connectionInvokeType][IsSuccessorNodeCount++] = callNode; SuccessorNodes[connectionInvokeType].Add(callNode); return this; @@ -199,6 +224,7 @@ namespace Serein.Library public CallNode AddChildNodeFail(CallNode callNode) { var connectionInvokeType = ConnectionInvokeType.IsFail; + ChildNodes[(int)connectionInvokeType][IsFailNodeCount++] = callNode; SuccessorNodes[connectionInvokeType].Add(callNode); return this; @@ -206,6 +232,7 @@ namespace Serein.Library public CallNode AddChildNodeError(CallNode callNode) { var connectionInvokeType = ConnectionInvokeType.IsError; + ChildNodes[(int)connectionInvokeType][IsErrorNodeCount++] = callNode; SuccessorNodes[connectionInvokeType].Add(callNode); return this; } @@ -240,7 +267,6 @@ namespace Serein.Library private static readonly DefaultObjectPool> _stackPool = new DefaultObjectPool>(new DefaultPooledObjectPolicy>()); - /// /// 开始执行 @@ -282,7 +308,6 @@ namespace Serein.Library #endregion #region 执行完成时更新栈 - // 首先将指定类别后继分支的所有节点逆序推入栈中 var nextNodes = currentNode.SuccessorNodes[context.NextOrientation]; for (int index = nextNodes.Count - 1; index >= 0; index--) @@ -345,11 +370,16 @@ namespace Serein.Library { private readonly IFlowCallTree flowCallTree; private readonly IFlowEnvironment flowEnvironment; + public static Serein.Library.Utils.ObjectPool FlowContextPool { get; set; } public LightweightFlowControl(IFlowCallTree flowCallTree, IFlowEnvironment flowEnvironment) { this.flowCallTree = flowCallTree; this.flowEnvironment = flowEnvironment; + FlowContextPool = new Utils.ObjectPool(() => + { + return new DynamicContext(flowEnvironment); + }); } public Task InvokeAsync(string apiGuid, Dictionary dict) @@ -368,11 +398,12 @@ namespace Serein.Library public async Task StartFlowAsync(string startNodeGuid) { - IDynamicContext context = new DynamicContext(flowEnvironment); + IDynamicContext context = Serein.Library.LightweightFlowControl.FlowContextPool.Allocate(); CancellationTokenSource cts = new CancellationTokenSource(); + FlowResult flowResult; #if DEBUG - FlowResult flowResult = await BenchmarkHelpers.BenchmarkAsync(async () => + flowResult = await BenchmarkHelpers.BenchmarkAsync(async () => { var node = flowCallTree.Get(startNodeGuid); var flowResult = await node.StartFlowAsync(context, cts.Token); @@ -380,7 +411,19 @@ namespace Serein.Library }); #else var node = flowCallTree.Get(startNodeGuid); - FlowResult flowResult = await node.StartFlowAsync(context, cts.Token); + try + { + flowResult = await node.StartFlowAsync(context, cts.Token); + } + catch (global::System.Exception) + { + throw; + } + finally + { + context.Reset(); + FlowContextPool.Free(context); + } #endif cts?.Cancel(); diff --git a/Library/FlowNode/SereinProjectData.cs b/Library/FlowNode/SereinProjectData.cs index 8b7a3f0..266d6bd 100644 --- a/Library/FlowNode/SereinProjectData.cs +++ b/Library/FlowNode/SereinProjectData.cs @@ -162,6 +162,16 @@ namespace Serein.Library /// public string Type { get; set; } + /// + /// 父节点集合 + /// + public Dictionary PreviousNodes { get; set; } + + /// + /// 后续节点集合 + /// + public Dictionary SuccessorNodes { get; set; } + /// /// 真分支节点GUID /// @@ -189,7 +199,7 @@ namespace Serein.Library /// - /// 父级节点Guid + /// 如果节点放置在了区域控件上,这里会有父级节点Guid /// public string ParentNodeGuid{ get; set; } diff --git a/Library/Utils/BenchmarkHelpers.cs b/Library/Utils/BenchmarkHelpers.cs index 99eb65e..46b207d 100644 --- a/Library/Utils/BenchmarkHelpers.cs +++ b/Library/Utils/BenchmarkHelpers.cs @@ -15,7 +15,7 @@ namespace Serein.Library.Utils /// /// 运行指定异步方法多次并输出耗时的最大、最小和平均值。 /// - /// 需要执行的异步方法 + /// 需要执行的方法 /// 执行次数,默认10000 public static void Benchmark(Action action, int count = 10000) { @@ -38,6 +38,7 @@ namespace Serein.Library.Utils double avg = total / count; Console.WriteLine($"运行 {count} 次:"); + Console.WriteLine($"总耗时 :{total} 毫秒:"); Console.WriteLine($"最大耗时:{max} 毫秒"); Console.WriteLine($"最小耗时:{min} 毫秒"); Console.WriteLine($"平均耗时:{avg} 毫秒"); diff --git a/NodeFlow/Env/FlowEdit.cs b/NodeFlow/Env/FlowEdit.cs index a809a04..a090bfe 100644 --- a/NodeFlow/Env/FlowEdit.cs +++ b/NodeFlow/Env/FlowEdit.cs @@ -504,6 +504,7 @@ namespace Serein.NodeFlow.Env #endregion await Task.Delay(100); + #region 确定节点之间的方法调用关系 foreach (var nodeInfo in nodeInfos) { @@ -513,14 +514,13 @@ namespace Serein.NodeFlow.Env return; } if (fromNodeModel is null) continue; - List<(ConnectionInvokeType connectionType, string[] guids)> allToNodes = [(ConnectionInvokeType.IsSucceed,nodeInfo.TrueNodes), - (ConnectionInvokeType.IsFail, nodeInfo.FalseNodes), - (ConnectionInvokeType.IsError, nodeInfo.ErrorNodes), - (ConnectionInvokeType.Upstream, nodeInfo.UpstreamNodes)]; - foreach ((ConnectionInvokeType connectionType, string[] toNodeGuids) item in allToNodes) + foreach (var kvp in nodeInfo.SuccessorNodes) { + var type = kvp.Key; + var nodes = kvp.Value; + if (nodes.Length == 0) continue; // 遍历当前类型分支的节点(确认连接关系) - foreach (var toNodeGuid in item.toNodeGuids) + foreach (var toNodeGuid in nodes) { if (!TryGetNodeModel(toNodeGuid, out var toNodeModel)) { @@ -531,17 +531,76 @@ namespace Serein.NodeFlow.Env // 防御性代码,加载正常保存的项目文件不会进入这里 continue; } - - ConnectInvokeNode(canvasGuid, fromNodeModel.Guid, toNodeModel.Guid, JunctionType.NextStep, JunctionType.Execute, item.connectionType); + if (fromNodeModel.SuccessorNodes[type].Contains(toNodeModel) || toNodeModel.PreviousNodes[type].Contains(fromNodeModel)) + { + continue; + } + ConnectInvokeNode(canvasGuid, fromNodeModel.Guid, toNodeModel.Guid, JunctionType.NextStep, JunctionType.Execute, type); } } + } + + foreach (var nodeInfo in nodeInfos) + { + var canvasGuid = nodeInfo.CanvasGuid; + if (!TryGetNodeModel(nodeInfo.Guid, out var toNodeModel)) + { + return; + } + if (toNodeModel is null) continue; + foreach (var kvp in nodeInfo.PreviousNodes) + { + var type = kvp.Key; + var nodes = kvp.Value; + if (nodes.Length == 0) continue; + // 遍历当前类型分支的节点(确认连接关系) + foreach (var toNodeGuid in nodes) + { + if (!TryGetNodeModel(toNodeGuid, out var fromNodeModel)) + { + return; + } + if (toNodeModel is null) + { + // 防御性代码,加载正常保存的项目文件不会进入这里 + continue; + } + if (fromNodeModel.SuccessorNodes[type].Contains(toNodeModel) || toNodeModel.PreviousNodes[type].Contains(fromNodeModel)) + { + continue; + } + ConnectInvokeNode(canvasGuid, fromNodeModel.Guid, toNodeModel.Guid, JunctionType.NextStep, JunctionType.Execute, type); + } + } + } + #endregion #region 确定节点之间的参数调用关系 - var nodeModels = flowModelService.GetAllNodeModel(); + foreach (var nodeInfo in nodeInfos) + { + var pdInfos = nodeInfo.ParameterData; + var toNodeGuid = nodeInfo.Guid; + for (global::System.Int32 index = 0; index < pdInfos.Length; index++) + { + var pdInfo = pdInfos[index]; + var fromNodeGuid = pdInfo.SourceNodeGuid; + if (!string.IsNullOrWhiteSpace(fromNodeGuid) && flowModelService.TryGetCanvasModel(fromNodeGuid,out var fromNode)) + { + continue; + } + var type = EnumHelper.ConvertEnum(pdInfo.SourceType); + var canvasGuid = nodeInfo.CanvasGuid; + ConnectArgSourceNode(canvasGuid, fromNodeGuid, toNodeGuid, JunctionType.ReturnData, JunctionType.ArgData, type,index); + + } + } + + + /* var nodeModels = flowModelService.GetAllNodeModel(); foreach (var toNode in nodeModels) { var canvasGuid = toNode.CanvasDetails.Guid; @@ -555,10 +614,16 @@ namespace Serein.NodeFlow.Env if (!string.IsNullOrEmpty(pd.ArgDataSourceNodeGuid) && TryGetNodeModel(pd.ArgDataSourceNodeGuid, out var fromNode)) { + *//*if (fromNode.NeedResultNodes[pd.ArgDataSourceType].Contains(toNode) + && pd.ArgDataSourceNodeGuid == fromNode.Guid + && ) + { + continue; + }*//* ConnectArgSourceNode(canvasGuid, fromNode.Guid, toNode.Guid, JunctionType.ReturnData, JunctionType.ArgData, pd.ArgDataSourceType, pd.Index); } } - } + }*/ #endregion diff --git a/NodeFlow/Services/FlowCoreGenerateService.cs b/NodeFlow/Services/FlowCoreGenerateService.cs index 6340a69..339af50 100644 --- a/NodeFlow/Services/FlowCoreGenerateService.cs +++ b/NodeFlow/Services/FlowCoreGenerateService.cs @@ -627,7 +627,7 @@ namespace Serein.NodeFlow.Services // 初始化 Get 函数 var nodeIndexName = "node_index"; - sb.AppendCode(2, $" [MethodImpl(MethodImplOptions.AggressiveInlining)]"); // 内联优化 + //sb.AppendCode(2, $" [MethodImpl(MethodImplOptions.AggressiveInlining)]"); // 内联优化 sb.AppendCode(2, $"public global::Serein.Library.CallNode {nameof(IFlowCallTree.Get)}( global::System.String key)"); sb.AppendCode(2, $"{{"); sb.AppendCode(3, $"global::System.Int32 {nodeIndexName};"); @@ -703,7 +703,6 @@ namespace Serein.NodeFlow.Services } - private void GenerateFlowApi_ApiParamClass(StringBuilder sb) { var infos = flowApiMethodInfos.Values.ToArray(); @@ -887,6 +886,7 @@ namespace Serein.NodeFlow.Services var contextImpleFullName = $"global::{typeof(DynamicContext).FullName}"; var tokenSourceFullName = $"global::{typeof(CancellationTokenSource).FullName}"; var tokenFullName = $"global::{typeof(CancellationToken).FullName}"; + var flowContextPoolName = $"global::{typeof(LightweightFlowControl).FullName}"; string flowEnvironment = nameof(flowEnvironment); string flowContext = nameof(flowContext); string token = nameof(token); @@ -902,11 +902,22 @@ namespace Serein.NodeFlow.Services var invokeParamSignature = string.Join(", ", ParamInfos.Select(p => p.ParamName)); sb.AppendCode(2, $"public async {returnTypeContext} {ApiMethodName}({paramSignature})"); sb.AppendCode(2, $"{{"); - sb.AppendCode(3, $"{contextApiFullName} {flowContext} = new {contextImpleFullName}({flowEnvironment}); // 创建上下文"); - sb.AppendCode(3, $"{tokenSourceFullName} cts = new {tokenSourceFullName}(); // 创建取消令牌"); - sb.AppendCode(3, $"await {ApiMethodName}({flowContext}, cts.Token, {invokeParamSignature}); // 调用目标方法"); - sb.AppendCode(3, $"{flowContext}.{nameof(IDynamicContext.Reset)}(); "); - sb.AppendCode(3, $"cts.{nameof(CancellationTokenSource.Dispose)}(); "); + sb.AppendCode(3, $"{contextApiFullName} {flowContext} = {flowContextPoolName}.{nameof(LightweightFlowControl.FlowContextPool)}.{nameof(LightweightFlowControl.FlowContextPool.Allocate)}(); // 从对象池获取一个上下文"); + sb.AppendCode(3, $"{tokenSourceFullName} cts = new {tokenSourceFullName}(); // 创建取消令牌"); + sb.AppendCode(3, $"try"); + sb.AppendCode(3, $"{{"); + sb.AppendCode(4, $"await {ApiMethodName}({flowContext}, cts.Token, {invokeParamSignature}); // 调用目标方法"); + sb.AppendCode(3, $"}}"); + sb.AppendCode(3, $"catch (Exception)"); + sb.AppendCode(3, $"{{"); + sb.AppendCode(4, $"throw;"); + sb.AppendCode(3, $"}}"); + sb.AppendCode(3, $"finally"); + sb.AppendCode(3, $"{{"); + sb.AppendCode(4, $"{flowContext}.{nameof(IDynamicContext.Reset)}(); "); + sb.AppendCode(4, $"cts.{nameof(CancellationTokenSource.Dispose)}(); "); + sb.AppendCode(4, $"{flowContextPoolName}.{nameof(LightweightFlowControl.FlowContextPool)}.{nameof(LightweightFlowControl.FlowContextPool.Free)}({flowContext}); // 释放上下文"); + sb.AppendCode(3, $"}}"); sb.AppendCode(2, $"}}"); return sb.ToString(); } @@ -916,9 +927,20 @@ namespace Serein.NodeFlow.Services var invokeParamSignature = string.Join(", ", ParamInfos.Select(p => p.ParamName)); sb.AppendCode(2, $"public async {returnTypeContext} {ApiMethodName}({tokenFullName} {token}, {paramSignature})"); sb.AppendCode(2, $"{{"); - sb.AppendCode(3, $"{contextApiFullName} {flowContext} = new {contextImpleFullName}({flowEnvironment}); // 创建上下文"); - sb.AppendCode(3, $"await {ApiMethodName}({flowContext}, {token}, {invokeParamSignature}); // 调用目标方法"); - sb.AppendCode(3, $"{flowContext}.{nameof(IDynamicContext.Reset)}(); "); + sb.AppendCode(3, $"{contextApiFullName} {flowContext} = {flowContextPoolName}.{nameof(LightweightFlowControl.FlowContextPool)}.{nameof(LightweightFlowControl.FlowContextPool.Allocate)}(); // 从对象池获取一个上下文"); + sb.AppendCode(3, $"try"); + sb.AppendCode(3, $"{{"); + sb.AppendCode(4, $"await {ApiMethodName}({flowContext}, {token}, {invokeParamSignature}); // 调用目标方法"); + sb.AppendCode(4, $"{flowContext}.{nameof(IDynamicContext.Reset)}(); "); + sb.AppendCode(3, $"}}"); + sb.AppendCode(3, $"catch (Exception)"); + sb.AppendCode(3, $"{{"); + sb.AppendCode(4, $"throw;"); + sb.AppendCode(3, $"}}"); + sb.AppendCode(3, $"finally"); + sb.AppendCode(3, $"{{"); + sb.AppendCode(4, $"{flowContextPoolName}.{nameof(LightweightFlowControl.FlowContextPool)}.{nameof(LightweightFlowControl.FlowContextPool.Free)}({flowContext}); // 释放上下文"); + sb.AppendCode(3, $"}}"); sb.AppendCode(2, $"}}"); return sb.ToString(); } @@ -930,21 +952,28 @@ namespace Serein.NodeFlow.Services sb.AppendCode(2, $"public async {returnTypeContext} {ApiMethodName}({contextApiFullName} {flowContext}, {tokenFullName} token, {paramSignature})"); sb.AppendCode(2, $"{{"); - sb.AppendCode(3, $"token.ThrowIfCancellationRequested(); // 检查任务是否取消"); - // 生成参数类实例化代码 - sb.AppendCode(3, $"global::{ParamTypeName} data = new global::{ParamTypeName}"); - sb.AppendCode(3, $"{{"); + sb.AppendCode(3, $"token.ThrowIfCancellationRequested(); // 检查任务是否取消"); + sb.AppendCode(3, $"try"); + sb.AppendCode(3, $"{{"); + sb.AppendCode(3, $"global::{ParamTypeName} data = {ObjPoolName}.Get(); // 从对象池获取一个对象"); for (int index = 0; index < ParamInfos.Count; index++) { ParamInfo? info = ParamInfos[index]; - sb.AppendCode(4, $"{info.ParamName.ToPascalCase()} = {info.ParamName}; // [{index}] {info.Comments}"); + sb.AppendCode(4, $"data.{info.ParamName.ToPascalCase()} = {info.ParamName}; // [{index}] {info.Comments}"); } - sb.AppendCode(3, $"}}"); - - sb.AppendCode(3, $"{flowContext}.{nameof(IDynamicContext.AddOrUpdate)}(\"{ApiMethodName}\", data);"); - sb.AppendCode(3, $"{flowContext}.{nameof(IDynamicContext.SetPreviousNode)}(\"{NodeModel.Guid}\", \"{ApiMethodName}\");"); - sb.AppendCode(3, $"global::{typeof(CallNode).FullName} node = Get(\"{NodeModel.Guid}\");"); - sb.AppendCode(3, $"await node.{nameof(CallNode.StartFlowAsync)}({flowContext}, {token}); // 调用目标方法"); + sb.AppendCode(3, $"{flowContext}.{nameof(IDynamicContext.AddOrUpdate)}(\"{ApiMethodName}\", data);"); + sb.AppendCode(3, $"{flowContext}.{nameof(IDynamicContext.SetPreviousNode)}(\"{NodeModel.TargetNode.Guid}\", \"{ApiMethodName}\");"); + sb.AppendCode(3, $"global::{typeof(CallNode).FullName} node = Get(\"{NodeModel.Guid}\");"); + sb.AppendCode(3, $"await node.{nameof(CallNode.StartFlowAsync)}({flowContext}, {token}); // 调用目标方法"); + sb.AppendCode(3, $"}}"); + sb.AppendCode(3, $"catch (Exception)"); + sb.AppendCode(3, $"{{"); + sb.AppendCode(4, $"throw;"); + sb.AppendCode(3, $"}}"); + sb.AppendCode(3, $"finally"); + sb.AppendCode(3, $"{{"); + sb.AppendCode(4, $"{flowContextPoolName}.{nameof(LightweightFlowControl.FlowContextPool)}.{nameof(LightweightFlowControl.FlowContextPool.Free)}({flowContext}); // 释放上下文"); + sb.AppendCode(3, $"}}"); sb.AppendCode(2, $"}}"); return sb.ToString(); } @@ -954,16 +983,29 @@ namespace Serein.NodeFlow.Services string flowResult = nameof(flowResult); if (type == ParamType.Defute) { + //sb.AppendCode(3, $"{contextApiFullName} {flowContext} = new {contextImpleFullName}({flowEnvironment}); // 创建上下文"); + var paramSignature = string.Join(", ", ParamInfos.Select(p => $"global::{p.Type.FullName} {p.ParamName}")); var invokeParamSignature = string.Join(", ", ParamInfos.Select(p => p.ParamName)); sb.AppendCode(2, $"public async {returnTypeContext} {ApiMethodName}({paramSignature})"); sb.AppendCode(2, $"{{"); - sb.AppendCode(3, $"{contextApiFullName} {flowContext} = new {contextImpleFullName}({flowEnvironment}); // 创建上下文"); - sb.AppendCode(3, $"{tokenSourceFullName} cts = new {tokenSourceFullName}(); // 创建取消令牌"); - sb.AppendCode(3, $"{ReturnType.FullName} {flowResult} = await {ApiMethodName}({flowContext}, cts.{nameof(CancellationTokenSource.Token)}, {invokeParamSignature}); // 调用目标方法"); - sb.AppendCode(3, $"{flowContext}.{nameof(IDynamicContext.Reset)}(); "); - sb.AppendCode(3, $"cts.{nameof(CancellationTokenSource.Dispose)}(); "); - sb.AppendCode(3, $"return {flowResult};"); + sb.AppendCode(3, $"{contextApiFullName} {flowContext} = {flowContextPoolName}.{nameof(LightweightFlowControl.FlowContextPool)}.{nameof(LightweightFlowControl.FlowContextPool.Allocate)}(); // 从对象池获取一个上下文"); + sb.AppendCode(3, $"{tokenSourceFullName} cts = new {tokenSourceFullName}(); // 创建取消令牌"); + sb.AppendCode(3, $"try"); + sb.AppendCode(3, $"{{"); + sb.AppendCode(4, $"{ReturnType.FullName} {flowResult} = await {ApiMethodName}({flowContext}, cts.{nameof(CancellationTokenSource.Token)}, {invokeParamSignature}); // 调用目标方法"); + sb.AppendCode(4, $"return {flowResult};"); + sb.AppendCode(3, $"}}"); + sb.AppendCode(3, $"catch (Exception)"); + sb.AppendCode(3, $"{{"); + sb.AppendCode(4, $"throw;"); + sb.AppendCode(3, $"}}"); + sb.AppendCode(3, $"finally"); + sb.AppendCode(3, $"{{"); + sb.AppendCode(4, $"{flowContext}.{nameof(IDynamicContext.Reset)}(); "); + sb.AppendCode(4, $"cts.{nameof(CancellationTokenSource.Dispose)}(); "); + sb.AppendCode(4, $"{flowContextPoolName}.{nameof(LightweightFlowControl.FlowContextPool)}.{nameof(LightweightFlowControl.FlowContextPool.Free)}({flowContext}); // 释放上下文"); + sb.AppendCode(3, $"}}"); sb.AppendCode(2, $"}}"); return sb.ToString(); } @@ -973,52 +1015,50 @@ namespace Serein.NodeFlow.Services var invokeParamSignature = string.Join(", ", ParamInfos.Select(p => p.ParamName)); sb.AppendCode(2, $"public async {returnTypeContext} {ApiMethodName}({tokenFullName} {token}, {paramSignature})"); sb.AppendCode(2, $"{{"); - sb.AppendCode(3, $"{contextApiFullName} {flowContext} = new {contextImpleFullName}({flowEnvironment}); // 创建上下文"); - sb.AppendCode(3, $"{ReturnType.FullName} {flowResult} = await {ApiMethodName}({flowContext}, {token}, {invokeParamSignature}); // 调用目标方法"); - sb.AppendCode(3, $"{flowContext}.{nameof(IDynamicContext.Reset)}(); "); - sb.AppendCode(3, $"return {flowResult};"); + sb.AppendCode(3, $"{contextApiFullName} {flowContext} = {flowContextPoolName}.{nameof(LightweightFlowControl.FlowContextPool)}.{nameof(LightweightFlowControl.FlowContextPool.Allocate)}(); // 从对象池获取一个上下文"); + sb.AppendCode(3, $"try"); + sb.AppendCode(3, $"{{"); + sb.AppendCode(4, $"{ReturnType.FullName} {flowResult} = await {ApiMethodName}({flowContext}, {token}, {invokeParamSignature}); // 调用目标方法"); + sb.AppendCode(4, $"return {flowResult};"); + sb.AppendCode(3, $"}}"); + sb.AppendCode(3, $"catch (Exception)"); + sb.AppendCode(3, $"{{"); + sb.AppendCode(4, $"throw;"); + sb.AppendCode(3, $"}}"); + sb.AppendCode(3, $"finally"); + sb.AppendCode(3, $"{{"); + sb.AppendCode(4, $"{flowContext}.{nameof(IDynamicContext.Reset)}(); "); + sb.AppendCode(4, $"{flowContextPoolName}.{nameof(LightweightFlowControl.FlowContextPool)}.{nameof(LightweightFlowControl.FlowContextPool.Free)}({flowContext}); // 释放上下文"); + sb.AppendCode(3, $"}}"); sb.AppendCode(2, $"}}"); return sb.ToString(); - } - - else if (type == ParamType.HasContextAndToken) { var paramSignature = string.Join(", ", ParamInfos.Select(p => $"global::{p.Type.FullName} {p.ParamName}")); var invokeParamSignature = string.Join(", ", ParamInfos.Select(p => p.ParamName)); sb.AppendCode(2, $"public async {returnTypeContext} {ApiMethodName}({contextApiFullName} {flowContext}, {tokenFullName} token, {paramSignature})"); sb.AppendCode(2, $"{{"); - sb.AppendCode(3, $"token.ThrowIfCancellationRequested(); // 检查任务是否取消"); - // 生成参数类实例化代码 - /*sb.AppendCode(3, $"global::{ParamTypeName} data = new global::{ParamTypeName}"); - sb.AppendCode(3, $"{{"); + sb.AppendCode(3, $"token.ThrowIfCancellationRequested(); // 检查任务是否取消"); + sb.AppendCode(3, $"global::{ParamTypeName} data = {ObjPoolName}.Get(); // 从对象池获取一个对象"); for (int index = 0; index < ParamInfos.Count; index++) { ParamInfo? info = ParamInfos[index]; - sb.AppendCode(4, $"{info.ParamName.ToPascalCase()} = {info.ParamName}; // [{index}] {info.Comments}"); + sb.AppendCode(4, $"data.{info.ParamName.ToPascalCase()} = {info.ParamName}; // [{index}] {info.Comments}"); // 进行赋值 } - sb.AppendCode(3, $"}}");*/ - sb.AppendCode(3, $"global::{ParamTypeName} data = {ObjPoolName}.Get(); // 从对象池获取一个对象"); - for (int index = 0; index < ParamInfos.Count; index++) - { - ParamInfo? info = ParamInfos[index]; - sb.AppendCode(4, $"data.{info.ParamName.ToPascalCase()} = {info.ParamName}; // [{index}] {info.Comments}"); - } - - sb.AppendCode(3, $"{flowContext}.{nameof(IDynamicContext.AddOrUpdate)}(\"{ApiMethodName}\", data);"); - sb.AppendCode(3, $"{flowContext}.{nameof(IDynamicContext.SetPreviousNode)}(\"{NodeModel.Guid}\", \"{ApiMethodName}\");"); - sb.AppendCode(3, $"global::{typeof(CallNode).FullName} node = Get(\"{NodeModel.Guid}\");"); - sb.AppendCode(3, $"global::{typeof(FlowResult).FullName} {flowResult} = await node.{nameof(CallNode.StartFlowAsync)}({flowContext}, {token}); // 调用目标方法"); - sb.AppendCode(3, $"if ({flowResult}.{nameof(FlowResult.Value)} is global::{ReturnType.FullName} result)"); - sb.AppendCode(3, $"{{"); - sb.AppendCode(4, $"return result;"); - sb.AppendCode(3, $"}}"); - sb.AppendCode(3, $"else"); - sb.AppendCode(3, $"{{"); - sb.AppendCode(4, $"throw new ArgumentNullException($\"类型转换失败,{{(flowResult.Value is null ? \"返回数据为 null\" : $\"返回数据与需求类型不匹配,当前返回类型为[{{flowResult.Value.GetType().FullName}}。\")}}\");"); - sb.AppendCode(3, $"}}"); - sb.AppendCode(3, $"return {flowResult};"); + sb.AppendCode(3, $"{flowContext}.{nameof(IDynamicContext.AddOrUpdate)}(\"{ApiMethodName}\", data);"); + sb.AppendCode(3, $"{flowContext}.{nameof(IDynamicContext.SetPreviousNode)}(\"{NodeModel.Guid}\", \"{ApiMethodName}\");"); + sb.AppendCode(3, $"global::{typeof(CallNode).FullName} node = Get(\"{NodeModel.Guid}\");"); + sb.AppendCode(3, $"global::{typeof(FlowResult).FullName} {flowResult} = await node.{nameof(CallNode.StartFlowAsync)}({flowContext}, {token}); // 调用目标方法"); + sb.AppendCode(3, $"if ({flowResult}.{nameof(FlowResult.Value)} is global::{ReturnType.FullName} result)"); + sb.AppendCode(3, $"{{"); + sb.AppendCode(4, $"return result;"); + sb.AppendCode(3, $"}}"); + sb.AppendCode(3, $"else"); + sb.AppendCode(3, $"{{"); + sb.AppendCode(4, $"throw new ArgumentNullException($\"类型转换失败,{{(flowResult.Value is null ? \"返回数据为 null\" : $\"返回数据与需求类型不匹配,当前返回类型为[{{flowResult.Value.GetType().FullName}}。\")}}\");"); + sb.AppendCode(3, $"}}"); + sb.AppendCode(3, $"return {flowResult};"); sb.AppendCode(2, $"}}"); return sb.ToString(); // throw new ArgumentNullException($"类型转换失败,{(flowResult.Value is null ? "返回数据为 null" : $"返回数据与需求类型不匹配,当前返回类型为[{flowResult.Value.GetType().FullName}。")}"); diff --git a/Workbench/Converters/BoolToVisibilityConverter.cs b/Workbench/Converters/BoolToVisibilityConverter.cs index 676924d..4e8b68f 100644 --- a/Workbench/Converters/BoolToVisibilityConverter.cs +++ b/Workbench/Converters/BoolToVisibilityConverter.cs @@ -14,7 +14,7 @@ namespace Serein.Workbench.Converters { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - Debug.WriteLine($"targetType:{targetType} value:{targetType} parameter:{parameter}"); + //Debug.WriteLine($"targetType:{targetType} value:{targetType} parameter:{parameter}"); if (value is bool b) { return b ? Visibility.Visible : Visibility.Collapsed;