diff --git a/Library/FlowNode/ParameterDetails.cs b/Library/FlowNode/ParameterDetails.cs index 80f0b2e..e572334 100644 --- a/Library/FlowNode/ParameterDetails.cs +++ b/Library/FlowNode/ParameterDetails.cs @@ -168,15 +168,57 @@ namespace Serein.Library IsParams = info.IsParams; } - + /// + /// 禁止将 IFlowContext 类型显式入参设置为 true + /// + /// + /// partial void BeforeTheIsExplicitData(ref bool __isAllow, bool newValue) { - if(DataType == typeof(IFlowContext)) + if(DataType == typeof(IFlowContext) && newValue == true) { __isAllow = false; } } + /// + /// 脚本节点的类型缓存。 + /// + private Type? cacheType; + private bool cacheIsExplicit; + + /// + /// 脚本节点的名称变更为流程上下文时,调整 DataType 和 IsExplicitData 的值。 + /// + /// + /// + partial void OnNameChanged(string oldValue, string newValue) + { + if (NodeModel is null) + return; + if (NodeModel.ControlType == NodeControlType.Script) + { + var isIgnore = StringComparison.OrdinalIgnoreCase; + if ("context".Equals(newValue, isIgnore) || + "flowcontext".Equals(newValue, isIgnore) || + "flow_context".Equals(newValue, isIgnore)) + { + cacheType = DataType; + cacheIsExplicit = IsExplicitData; + DataType = typeof(IFlowContext); + IsExplicitData = false; + } + else + { + if (cacheType is not null) + { + DataType = cacheType; + IsExplicitData = cacheIsExplicit; + } + } + } + } + /// /// 转为描述 diff --git a/NodeFlow/Model/Nodes/SingleConditionNode.cs b/NodeFlow/Model/Nodes/SingleConditionNode.cs index 38a9f10..1f7e290 100644 --- a/NodeFlow/Model/Nodes/SingleConditionNode.cs +++ b/NodeFlow/Model/Nodes/SingleConditionNode.cs @@ -223,7 +223,7 @@ namespace Serein.NodeFlow.Model.Nodes } - IScriptInvokeContext scriptContext = new ScriptInvokeContext(flowContext); + IScriptInvokeContext scriptContext = new ScriptInvokeContext(); scriptContext.SetVarValue(dataName, data); var result = await getValueScript.InterpreterAsync(scriptContext); @@ -262,7 +262,7 @@ namespace Serein.NodeFlow.Model.Nodes }); } - IScriptInvokeContext scriptContext = new ScriptInvokeContext(flowContext); + IScriptInvokeContext scriptContext = new ScriptInvokeContext(); scriptContext.SetVarValue(dataName, data); var result = await conditionScript.InterpreterAsync(scriptContext); diff --git a/NodeFlow/Model/Nodes/SingleExpOpNode.cs b/NodeFlow/Model/Nodes/SingleExpOpNode.cs index 2e7397c..61f9226 100644 --- a/NodeFlow/Model/Nodes/SingleExpOpNode.cs +++ b/NodeFlow/Model/Nodes/SingleExpOpNode.cs @@ -178,7 +178,7 @@ namespace Serein.NodeFlow.Model.Nodes } - IScriptInvokeContext scriptContext = new ScriptInvokeContext(flowContext); + IScriptInvokeContext scriptContext = new ScriptInvokeContext(); scriptContext.SetVarValue(dataName, data); var result = await getValueScript.InterpreterAsync(scriptContext); diff --git a/NodeFlow/Model/Nodes/SingleScriptNode.cs b/NodeFlow/Model/Nodes/SingleScriptNode.cs index e4f4227..1807748 100644 --- a/NodeFlow/Model/Nodes/SingleScriptNode.cs +++ b/NodeFlow/Model/Nodes/SingleScriptNode.cs @@ -1,6 +1,7 @@ using Serein.Library; using Serein.Library.Api; using Serein.Library.Utils; +using Serein.NodeFlow.Services; using Serein.Script; using Serein.Script.Node.FlowControl; using System; @@ -49,7 +50,6 @@ namespace Serein.NodeFlow.Model.Nodes public SingleScriptNode(IFlowEnvironment environment) : base(environment) { sereinScript = new SereinScript(); - } static SingleScriptNode() @@ -195,7 +195,11 @@ namespace Serein.NodeFlow.Model.Nodes ScriptArgInfo[] array = JsonHelper.Deserialize(paramsTypeNameJson); string returnTypeName = nodeInfo.CustomData?.ReturnTypeName ?? typeof(object); - Type?[] argType = array.Select(item => string.IsNullOrWhiteSpace(item.ArgType) ? null : Type.GetType(item.ArgType) ?? typeof(Unit)).ToArray(); + + var flowLibService = Env.IOC.Get(); + + Type?[] argType = array.Select(item => string.IsNullOrWhiteSpace(item.ArgType) ? null : flowLibService.GetType(item.ArgType) ?? typeof(Unit)).ToArray(); + Type? resType = Type.GetType(returnTypeName); for (int i = 0; i < paramCount; i++) { @@ -352,7 +356,7 @@ namespace Serein.NodeFlow.Model.Nodes var @params = await flowCallNode.GetParametersAsync(context, token); - IScriptInvokeContext scriptContext = new ScriptInvokeContext(context); + IScriptInvokeContext scriptContext = new ScriptInvokeContext(); if (@params[0] is object[] agrDatas) { diff --git a/NodeFlow/Model/Operations/ChangeNodeConnectionOperation.cs b/NodeFlow/Model/Operations/ChangeNodeConnectionOperation.cs index 4f3e63b..2700059 100644 --- a/NodeFlow/Model/Operations/ChangeNodeConnectionOperation.cs +++ b/NodeFlow/Model/Operations/ChangeNodeConnectionOperation.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Reactive; +using System.Reflection; using System.Security.AccessControl; using System.Text; using System.Threading.Tasks; @@ -429,6 +430,11 @@ namespace Serein.NodeFlow.Model.Operations return false; } + if (typeof(IFlowContext).IsAssignableFrom(ToNode.MethodDetails.ParameterDetailss[ArgIndex].DataType)) + { + SereinEnv.WriteLine(InfoType.WARN, $"连接失败, IFlowContext 流程上下文由运行环境自动注入,作为节点入参时不允许外部给定。起始节点[{FromNode.Guid}],目标节点[{FromNode.Guid}]。"); + return false; + } var toNodeArgSourceGuid = ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceNodeGuid; // 目标节点对应参数可能已经有其它连接 var toNodeArgSourceType = ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceType; diff --git a/NodeFlow/Services/FlowLibraryService.cs b/NodeFlow/Services/FlowLibraryService.cs index 499ca4d..02b1360 100644 --- a/NodeFlow/Services/FlowLibraryService.cs +++ b/NodeFlow/Services/FlowLibraryService.cs @@ -147,6 +147,46 @@ namespace Serein.NodeFlow.Services #region 获取流程依赖的相关方法 + /// + /// 搜索类型 + /// + /// + /// + /// + public bool TryGetType(string fullName,[NotNullWhen(true)] out Type? type) + { + var assemblys = _flowLibraryCaches.Values.Select(key => key.Assembly).ToArray(); + foreach(var assembly in assemblys) + { + type = assembly.GetType(fullName); + if(type is not null) + { + return true; + } + } + type = null; + return false; + } + /// + /// 搜索类型 + /// + /// + /// + public Type? GetType(string fullName) + { + var assemblys = _flowLibraryCaches.Values.Select(key => key.Assembly).ToArray(); + Type? type; + foreach (var assembly in assemblys) + { + type = assembly.GetType(fullName); + if(type is not null) + { + return type; + } + } + return null; + } + /// /// 获取方法描述 /// diff --git a/Serein.Script/IScriptInvokeContext.cs b/Serein.Script/IScriptInvokeContext.cs index a5dfa3c..c842a8a 100644 --- a/Serein.Script/IScriptInvokeContext.cs +++ b/Serein.Script/IScriptInvokeContext.cs @@ -7,10 +7,6 @@ namespace Serein.Script /// public interface IScriptInvokeContext { - /// - /// 脚本运行的流程上下文,包含了流程上下文和变量等信息 - /// - IFlowContext FlowContext { get; } /// /// 是否该退出了(由 TokenSource 控制,用于响应外部发出停止信号) diff --git a/Serein.Script/ScriptInvokeContext.cs b/Serein.Script/ScriptInvokeContext.cs index 8d3b71c..7ad1b15 100644 --- a/Serein.Script/ScriptInvokeContext.cs +++ b/Serein.Script/ScriptInvokeContext.cs @@ -4,15 +4,6 @@ namespace Serein.Script { public sealed class ScriptInvokeContext : IScriptInvokeContext { - /// - /// 脚本使用流程上下文 - /// - /// - public ScriptInvokeContext(IFlowContext flowContext) - { - FlowContext = flowContext; - } - /// /// 不使用流程上下文 /// @@ -20,10 +11,6 @@ namespace Serein.Script { } -#pragma warning disable CS8766 // 返回类型中引用类型的为 Null 性与隐式实现的成员不匹配(可能是由于为 Null 性特性)。 - public IFlowContext? FlowContext{ get; } -#pragma warning restore CS8766 // 返回类型中引用类型的为 Null 性与隐式实现的成员不匹配(可能是由于为 Null 性特性)。 - /// /// 定义的变量 /// diff --git a/Serein.Script/SereinScriptInterpreter.cs b/Serein.Script/SereinScriptInterpreter.cs index 139d6a7..8583a3c 100644 --- a/Serein.Script/SereinScriptInterpreter.cs +++ b/Serein.Script/SereinScriptInterpreter.cs @@ -13,10 +13,10 @@ namespace Serein.Script public class SereinScriptInterpreter { private readonly Dictionary symbolInfos; + /// /// 缓存对象方法调用节点 /// - //private Dictionary MethodNodeDelegateCaches { get; } = new Dictionary(); private static Dictionary ASTDelegateDetails { get; } = new Dictionary(); @@ -322,15 +322,6 @@ namespace Serein.Script case FunctionCallNode functionCallNode: // 外部挂载的函数调用 async Task InterpreterFunctionCallNodeAsync(IScriptInvokeContext context, FunctionCallNode functionCallNode) { - // 获取流程上下文 - if (context.FlowContext != null && functionCallNode.FunctionName.Equals("getFlowContext", StringComparison.OrdinalIgnoreCase)) - { - return context.FlowContext; - } - else if (functionCallNode.FunctionName.Equals("getScriptContext", StringComparison.OrdinalIgnoreCase)) - { - return context; - } // 获取参数 var arguments = functionCallNode.Arguments.Count == 0 ? [] : diff --git a/Workbench/Themes/MethodDetailsControl.xaml b/Workbench/Themes/MethodDetailsControl.xaml index 074594e..eb22be5 100644 --- a/Workbench/Themes/MethodDetailsControl.xaml +++ b/Workbench/Themes/MethodDetailsControl.xaml @@ -52,7 +52,7 @@ - + @@ -73,7 +73,7 @@ - +