尝试将节点流导出为c#代码文件

This commit is contained in:
fengjiayi
2025-07-06 14:34:49 +08:00
parent 162dc7bcf8
commit b25fd9c83c
45 changed files with 1625 additions and 361 deletions

View File

@@ -46,6 +46,26 @@ namespace Serein.Library
/// </summary>
public Exception ExceptionOfRuning { get; set; }
/// <summary>
/// 每个流程上下文分别存放节点的当前数据
/// </summary>
private readonly ConcurrentDictionary<string, FlowResult> dictNodeFlowData = new ConcurrentDictionary<string, FlowResult>();
/// <summary>
/// 每个流程上下文存储运行时节点的调用关系
/// </summary>
private readonly ConcurrentDictionary<string, string> dictPreviousNodes = new ConcurrentDictionary<string, string>();
/// <summary>
/// 记录忽略处理的流程
/// </summary>
private readonly ConcurrentDictionary<string, bool> dictIgnoreNodeFlow = new ConcurrentDictionary<string, bool>();
/// <summary>
/// 记录节点的运行时参数数据
/// </summary>
private readonly ConcurrentDictionary<string, ConcurrentDictionary<int, object>> dictNodeParams = new ConcurrentDictionary<string, ConcurrentDictionary<int, object>>();
/*
/// <summary>
/// 每个流程上下文分别存放节点的当前数据
/// </summary>
@@ -61,12 +81,70 @@ namespace Serein.Library
/// </summary>
private readonly ConcurrentDictionary<IFlowNode, bool> dictIgnoreNodeFlow = new ConcurrentDictionary<IFlowNode, bool>();
/// <summary>
/// 记录节点的运行时参数数据
/// </summary>
private readonly ConcurrentDictionary<IFlowNode, ConcurrentDictionary<int, object>> dictNodeParams = new ConcurrentDictionary<IFlowNode, ConcurrentDictionary<int, object>>();*/
/// <summary>
/// 设置节点的运行时参数数据
/// </summary>
/// <param name="nodeModel">节点</param>
/// <param name="index">第几个参数</param>
/// <param name="data">数据</param>
public void SetParamsTempData(string nodeModel, int index, object data)
{
if(!dictNodeParams.TryGetValue(nodeModel,out var dict))
{
dict = new ConcurrentDictionary<int, object>();
dictNodeParams[nodeModel] = dict;
}
if (dict.TryGetValue(index, out var oldData))
{
dict[index] = data; // 更新数据
}
else
{
dict.TryAdd(index, data); // 添加新数据
}
}
/// <summary>
/// 获取节点的运行时参数数据
/// </summary>
/// <param name="nodeModel">节点</param>
/// <param name="index">第几个参数</param>
public bool TryGetParamsTempData(string nodeModel, int index, out object data )
{
if (dictNodeParams.TryGetValue(nodeModel, out var dict))
{
if (dict.TryGetValue(index, out data))
{
return true; // 返回数据
}
else
{
//throw new KeyNotFoundException($"节点 {nodeModel.Guid} 的参数索引 {index} 不存在。");
data = null; // 返回空数据
return false; // 返回未找到
}
}
else
{
//throw new KeyNotFoundException($"节点 {nodeModel.Guid} 的参数数据不存在。");
data = null; // 返回空数据
return false; // 返回未找到
}
}
/// <summary>
/// 设置运行时上一节点
/// </summary>
/// <param name="currentNodeModel">当前节点</param>
/// <param name="PreviousNode">上一节点</param>
public void SetPreviousNode(IFlowNode currentNodeModel, IFlowNode PreviousNode)
public void SetPreviousNode(string currentNodeModel, string PreviousNode)
{
dictPreviousNodes.AddOrUpdate(currentNodeModel, (_) => PreviousNode, (o, n) => PreviousNode);
}
@@ -75,7 +153,7 @@ namespace Serein.Library
/// 忽略处理该节点流程
/// </summary>
/// <param name="node"></param>
public void IgnoreFlowHandle(IFlowNode node)
public void IgnoreFlowHandle(string node)
{
dictIgnoreNodeFlow.AddOrUpdate(node, (o) => true, (o, n) => true);
}
@@ -85,7 +163,7 @@ namespace Serein.Library
/// </summary>
/// <param name="node"></param>
/// <returns></returns>
public bool GetIgnodeFlowStateUpload(IFlowNode node)
public bool GetIgnodeFlowStateUpload(string node)
{
return dictIgnoreNodeFlow.TryGetValue(node, out var state) ? state : false;
}
@@ -94,7 +172,7 @@ namespace Serein.Library
/// </summary>
/// <param name="node"></param>
/// <returns></returns>
public void RecoverIgnodeFlowStateUpload(IFlowNode node)
public void RecoverIgnodeFlowStateUpload(string node)
{
dictIgnoreNodeFlow.AddOrUpdate(node, (o) => false, (o, n) => false);
}
@@ -105,7 +183,7 @@ namespace Serein.Library
/// </summary>
/// <param name="currentNodeModel"></param>
/// <returns></returns>
public IFlowNode GetPreviousNode(IFlowNode currentNodeModel)
public string GetPreviousNode(string currentNodeModel)
{
if (dictPreviousNodes.TryGetValue(currentNodeModel, out var node))
{
@@ -122,7 +200,7 @@ namespace Serein.Library
/// </summary>
/// <param name="nodeGuid">节点</param>
/// <returns></returns>
public FlowResult GetFlowData(IFlowNode nodeGuid)
public FlowResult GetFlowData(string nodeGuid)
{
if (dictNodeFlowData.TryGetValue(nodeGuid, out var data))
{
@@ -139,7 +217,7 @@ namespace Serein.Library
/// </summary>
/// <param name="nodeModel">节点</param>
/// <param name="flowData">新的数据</param>
public void AddOrUpdate(IFlowNode nodeModel, FlowResult flowData)
public void AddOrUpdate(string nodeModel, FlowResult flowData)
{
// this.dictNodeFlowData.TryGetValue(nodeGuid, out var oldFlowData);
dictNodeFlowData.AddOrUpdate(nodeModel, _ => flowData, (o,n ) => flowData);
@@ -149,7 +227,7 @@ namespace Serein.Library
/// 上一节点数据透传到下一节点
/// </summary>
/// <param name="nodeModel"></param>
public FlowResult TransmissionData(IFlowNode nodeModel)
public FlowResult TransmissionData(string nodeModel)
{
if (dictPreviousNodes.TryGetValue(nodeModel, out var previousNode)) // 首先获取当前节点的上一节点
{
@@ -159,7 +237,7 @@ namespace Serein.Library
//AddOrUpdate(nodeModel.Guid, data); // 然后作为当前节点的数据记录在上下文中
}
}
throw new InvalidOperationException($"透传{nodeModel.Guid}节点数据时发生异常:上一节点不存在数据");
throw new InvalidOperationException($"透传{nodeModel}节点数据时发生异常:上一节点不存在数据");
}
/// <summary>
@@ -280,6 +358,7 @@ namespace Serein.Library
list.Clear();
}
private void Dispose(ref IList<object> list)
{
foreach (var nodeObj in list)

View File

@@ -29,14 +29,15 @@ namespace Serein.Library
/// <summary>
/// 画布拥有的节点
/// </summary>
[PropertyInfo(IsProtection = true)]
private System.Collections.ObjectModel.ObservableCollection<IFlowNode> _nodes = [];
[PropertyInfo(IsProtection = false)]
private List<IFlowNode> _nodes = [];
//private System.Collections.ObjectModel.ObservableCollection<IFlowNode> _nodes = [];
/// <summary>
/// 画布公开的节点
/// </summary>
[PropertyInfo(IsProtection = true)]
private System.Collections.ObjectModel.ObservableCollection<IFlowNode> _publicNodes = [];
[PropertyInfo(IsProtection = false)]
private List<IFlowNode> _publicNodes = [];
/// <summary>
/// 标识画布ID

View File

@@ -28,11 +28,11 @@ namespace Serein.Library
/// <summary>
/// 实例化返回值
/// </summary>
/// <param name="nodeModel"></param>
/// <param name="nodeGuid"></param>
/// <param name="context"></param>
public FlowResult(IFlowNode nodeModel, IDynamicContext context, object value)
public FlowResult(string nodeGuid, IDynamicContext context, object value)
{
this.Source = nodeModel;
this.SourceNodeGuid = nodeGuid;
this.ContextGuid = context.Guid;
this.Value = value;
}
@@ -40,11 +40,11 @@ namespace Serein.Library
/// <summary>
/// 空返回值
/// </summary>
/// <param name="nodeModel"></param>
/// <param name="nodeGuid"></param>
/// <param name="context"></param>
public FlowResult(IFlowNode nodeModel, IDynamicContext context)
public FlowResult(string nodeGuid, IDynamicContext context)
{
this.Source = nodeModel;
this.SourceNodeGuid = nodeGuid;
this.ContextGuid = context.Guid;
this.Value = Unit.Default;
}
@@ -76,7 +76,7 @@ namespace Serein.Library
/// <summary>
/// 来源节点Guid
/// </summary>
public IFlowNode Source{ get; }
public string SourceNodeGuid{ get; }
/// <summary>
/// 来源上下文Guid
/// </summary>

View File

@@ -0,0 +1,625 @@
using Microsoft.VisualBasic;
using Serein.Library.Api;
using Serein.Library.Utils;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Serein.Library.FlowNode
{
/*public class FlowControl
{
private DynamicFlowTemplate dynamicFlowTemplate;
private LightweightEnvironment environment;
public FlowControl(DynamicFlowTemplate dynamicFlowTemplate,
LightweightEnvironment environment)
{
var callTree = new CallTree()
callTree.SetMainNode("node1_guid");
callTree.AddCallNode("node1_guid", (context) => DynamicFlowTemplate.Method(context, ...));
callTree.AddCallNode("node2_guid", (context) => DynamicFlowTemplate.Method(context, ...));
callTree.AddCallNode("node3_guid", (context) => DynamicFlowTemplate.Method(context, ...));
callTree.AddCallNode("node4_guid", (context) => DynamicFlowTemplate.Method(context, ...));
callTree["node1_guid"].AddFlowUpstream("node2_guid");
callTree["node1_guid"].AddFlowSucceed("node2_guid");
callTree["node2_guid"].AddFlowSucceed("node3_guid");
callTree["node2_guid"].AddFlowError("node4_guid");
LightweightEnvironment.LoadProject(callTree);
}
}*/
/*public class DynamicFlowTemplate
{
private readonly class1_type class1_instance;
public DynamicFlowTemplate(class1_type class_instance){
this.class1_instance = class1_instance;
}
[Description("node1_guid")]
[Description("assembly_name.class_name.method_name")]
private [methodReturnType / void] NodeMethod_[method_name](IDynamicContext context, type1 param1, type2 param2)
{
class1_instance.method(params);
context.SetData("node_guid", null);
}
[Description("node2_guid")]
[Description("assembly_name.class_name.method_name")]
private [methodReturnType] NodeMethod_[method_name](IDynamicContext context, type1 param1)
{
param1 = context.GetData("node1_guid") as type1;
var result = class1_instance.method(params, param1);
context.SetData("node2_guid", result);
}
[Description("node3_guid")]
public [methodReturnType] FlowCall_[method_name](IDynamicContext context, type1 param1, type2 param2)
{
param1 = context.GetData("node3_guid") as type1;
var result = class1_instance.method(params, param1);
context.SetData("node3_guid", result);
}
}
*/
public class CallTree
{
public CallTree(string canvasGuid, string startNodeGuid)
{
_canvas_guid = canvasGuid;
_start_node_guid = startNodeGuid;
}
private readonly ConcurrentDictionary<string, CallNode> _callNodes = new ConcurrentDictionary<string,CallNode>();
private readonly string _start_node_guid;
private readonly string _canvas_guid ;
public CallNode this[string index]
{
get
{
_callNodes.TryGetValue(index, out CallNode callNode);
return callNode;
}
set
{
// 设置指定索引的值
_callNodes.AddOrUpdate(index, value, (key, oldValue) => value);
}
}
public void AddCallNode(string nodeGuid, Action<IDynamicContext> action)
{
var node = new CallNode(this, nodeGuid, action);
_callNodes[nodeGuid] = node;
}
public void AddCallNode(string nodeGuid, Func<IDynamicContext, Task> func)
{
var node = new CallNode(this, nodeGuid, func);
_callNodes[nodeGuid] = node;
}
}
public class CallNode
{
private readonly Func<IDynamicContext, Task> func;
private readonly CallTree callTree;
private readonly Action<IDynamicContext> action;
public CallNode(CallTree callTree, string nodeGuid, Action<IDynamicContext> action)
{
this.callTree = callTree;
Guid = nodeGuid;
this.action = action;
}
public CallNode(CallTree callTree, string nodeGuid, Func<IDynamicContext, Task> func)
{
Guid = nodeGuid;
this.func = func;
Init();
}
private void Init()
{
PreviousNodes = new Dictionary<ConnectionInvokeType, List<CallNode>>();
SuccessorNodes = new Dictionary<ConnectionInvokeType, List<CallNode>>();
foreach (ConnectionInvokeType ctType in NodeStaticConfig.ConnectionTypes)
{
PreviousNodes[ctType] = new List<CallNode>();
SuccessorNodes[ctType] = new List<CallNode>();
}
}
/// <summary>
/// 对应的节点
/// </summary>
public string Guid { get; }
/// <summary>
/// 不同分支的父节点(流程调用)
/// </summary>
public Dictionary<ConnectionInvokeType, List<CallNode>> PreviousNodes { get; private set; }
/// <summary>
/// 不同分支的子节点(流程调用)
/// </summary>
public Dictionary<ConnectionInvokeType, List<CallNode>> SuccessorNodes { get; private set; }
public CallNode AddChildNodeUpstream(string nodeGuid)
{
var connectionInvokeType = ConnectionInvokeType.Upstream;
PreviousNodes[connectionInvokeType].Add(callTree[nodeGuid]);
return this;
}
public CallNode AddChildNodeSucceed(string nodeGuid)
{
var connectionInvokeType = ConnectionInvokeType.IsSucceed;
PreviousNodes[connectionInvokeType].Add(callTree[nodeGuid]);
return this;
}
public CallNode AddChildNodeFail(string nodeGuid)
{
var connectionInvokeType = ConnectionInvokeType.IsFail;
PreviousNodes[connectionInvokeType].Add(callTree[nodeGuid]);
return this;
}
public CallNode AddChildNodeError(string nodeGuid)
{
var connectionInvokeType = ConnectionInvokeType.IsError;
PreviousNodes[connectionInvokeType].Add(callTree[nodeGuid]);
return this;
}
/// <summary>
/// 调用
/// </summary>
/// <param name="context"></param>
/// <param name="token"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
public async Task InvokeAsync(IDynamicContext context, CancellationToken token)
{
if (token.IsCancellationRequested)
{
return;
}
if (action is not null)
{
action(context);
}
else if (func is not null)
{
await func(context);
}
else
{
throw new InvalidOperationException($"生成了错误的CallNode。【{Guid}】");
}
}
/// <summary>
/// 开始执行
/// </summary>
/// <param name="context"></param>
/// <param name="token">流程运行</param>
/// <returns></returns>
public async Task<FlowResult> StartFlowAsync(IDynamicContext context, CancellationToken token)
{
Stack<CallNode> stack = new Stack<CallNode>();
HashSet<CallNode> processedNodes = new HashSet<CallNode>(); // 用于记录已处理上游节点的节点
stack.Push(this);
while (true)
{
if (token.IsCancellationRequested)
{
throw new Exception($"流程执行被取消,未能获取到流程结果。");
}
#region
// 从栈中弹出一个节点作为当前节点进行处理
var currentNode = stack.Pop();
context.NextOrientation = ConnectionInvokeType.None; // 重置上下文状态
FlowResult flowResult = null;
try
{
await currentNode.InvokeAsync(context, token);
if (context.NextOrientation == ConnectionInvokeType.None) // 没有手动设置时,进行自动设置
{
context.NextOrientation = ConnectionInvokeType.IsSucceed;
}
}
catch (Exception ex)
{
flowResult = new FlowResult(currentNode.Guid, context);
context.Env.WriteLine(InfoType.ERROR, $"节点[{currentNode}]异常:" + ex);
context.NextOrientation = ConnectionInvokeType.IsError;
context.ExceptionOfRuning = ex;
}
#endregion
#region
context.AddOrUpdate(currentNode.Guid, flowResult); // 上下文中更新数据
// 首先将指定类别后继分支的所有节点逆序推入栈中
var nextNodes = currentNode.SuccessorNodes[context.NextOrientation];
for (int index = nextNodes.Count - 1; index >= 0; index--)
{
//if (!ignodeState)
context.SetPreviousNode(nextNodes[index].Guid, currentNode.Guid);
stack.Push(nextNodes[index]);
}
// 然后将指上游分支的所有节点逆序推入栈中
var upstreamNodes = currentNode.SuccessorNodes[ConnectionInvokeType.Upstream];
for (int index = upstreamNodes.Count - 1; index >= 0; index--)
{
context.SetPreviousNode(upstreamNodes[index].Guid, currentNode.Guid);
stack.Push(upstreamNodes[index]);
}
#endregion
#region
if (stack.Count == 0)
{
return flowResult; // 说明流程到了终点
}
if (context.RunState == RunState.Completion)
{
context.Env.WriteLine(InfoType.INFO, $"流程执行到节点[{currentNode.Guid}]时提前结束,将返回当前执行结果。");
return flowResult; // 流程执行完成,返回结果
}
if (token.IsCancellationRequested)
{
throw new Exception($"流程执行到节点[{currentNode.Guid}]时被取消,未能获取到流程结果。");
}
#endregion
}
}
}
/// <summary>
/// 轻量级流程控制器
/// </summary>
public class LightweightFlowControl : IFlowControl
{
private readonly Dictionary<string, CallTree> callTree = new Dictionary<string, CallTree>();
public LightweightFlowControl()
{
}
public Task<object> InvokeAsync(string apiGuid, Dictionary<string, object> dict)
{
throw new NotImplementedException();
}
public Task<TResult> InvokeAsync<TResult>(string apiGuid, Dictionary<string, object> dict)
{
throw new NotImplementedException();
}
public Task<bool> StartFlowFromSelectNodeAsync(string startNodeGuid)
{
throw new NotImplementedException();
}
public async Task<bool> StartFlowAsync(string[] canvasGuids)
{
throw new NotImplementedException();
}
public Task<bool> ExitFlowAsync()
{
throw new NotImplementedException();
}
#region
public void ActivateFlipflopNode(string nodeGuid)
{
throw new NotImplementedException();
}
public void MonitorObjectNotification(string nodeGuid, object monitorData, MonitorObjectEventArgs.ObjSourceType sourceType)
{
throw new NotImplementedException();
}
public void TerminateFlipflopNode(string nodeGuid)
{
throw new NotImplementedException();
}
public void TriggerInterrupt(string nodeGuid, string expression, InterruptTriggerEventArgs.InterruptTriggerType type)
{
throw new NotImplementedException();
}
public void UseExternalIOC(ISereinIOC ioc)
{
throw new NotImplementedException();
}
#endregion
}
/// <summary>
/// 轻量级流程环境事件实现
/// </summary>
public class LightweightFlowEnvironmentEvent : IFlowEnvironmentEvent
{
public event LoadDllHandler DllLoad;
public event ProjectLoadedHandler ProjectLoaded;
public event ProjectSavingHandler ProjectSaving;
public event NodeConnectChangeHandler NodeConnectChanged;
public event CanvasCreateHandler CanvasCreated;
public event CanvasRemoveHandler CanvasRemoved;
public event NodeCreateHandler NodeCreated;
public event NodeRemoveHandler NodeRemoved;
public event NodePlaceHandler NodePlace;
public event NodeTakeOutHandler NodeTakeOut;
public event StartNodeChangeHandler StartNodeChanged;
public event FlowRunCompleteHandler FlowRunComplete;
public event MonitorObjectChangeHandler MonitorObjectChanged;
public event NodeInterruptStateChangeHandler NodeInterruptStateChanged;
public event ExpInterruptTriggerHandler InterruptTriggered;
public event IOCMembersChangedHandler IOCMembersChanged;
public event NodeLocatedHandler NodeLocated;
public event EnvOutHandler EnvOutput;
public void OnDllLoad(LoadDllEventArgs eventArgs)
{
DllLoad?.Invoke(eventArgs);
}
public void OnProjectLoaded(ProjectLoadedEventArgs eventArgs)
{
ProjectLoaded?.Invoke(eventArgs);
}
public void OnProjectSaving(ProjectSavingEventArgs eventArgs)
{
ProjectSaving?.Invoke(eventArgs);
}
public void OnNodeConnectChanged(NodeConnectChangeEventArgs eventArgs)
{
NodeConnectChanged?.Invoke(eventArgs);
}
public void OnCanvasCreated(CanvasCreateEventArgs eventArgs)
{
CanvasCreated?.Invoke(eventArgs);
}
public void OnCanvasRemoved(CanvasRemoveEventArgs eventArgs)
{
CanvasRemoved?.Invoke(eventArgs);
}
public void OnNodeCreated(NodeCreateEventArgs eventArgs)
{
NodeCreated?.Invoke(eventArgs);
}
public void OnNodeRemoved(NodeRemoveEventArgs eventArgs)
{
NodeRemoved?.Invoke(eventArgs);
}
public void OnNodePlace(NodePlaceEventArgs eventArgs)
{
NodePlace?.Invoke(eventArgs);
}
public void OnNodeTakeOut(NodeTakeOutEventArgs eventArgs)
{
NodeTakeOut?.Invoke(eventArgs);
}
public void OnStartNodeChanged(StartNodeChangeEventArgs eventArgs)
{
StartNodeChanged?.Invoke(eventArgs);
}
public void OnFlowRunComplete(FlowEventArgs eventArgs)
{
FlowRunComplete?.Invoke(eventArgs);
}
public void OnMonitorObjectChanged(MonitorObjectEventArgs eventArgs)
{
MonitorObjectChanged?.Invoke(eventArgs);
}
public void OnNodeInterruptStateChanged(NodeInterruptStateChangeEventArgs eventArgs)
{
NodeInterruptStateChanged?.Invoke(eventArgs);
}
public void OnInterruptTriggered(InterruptTriggerEventArgs eventArgs)
{
InterruptTriggered?.Invoke(eventArgs);
}
public void OnIOCMembersChanged(IOCMembersChangedEventArgs eventArgs)
{
IOCMembersChanged?.Invoke(eventArgs);
}
public void OnNodeLocated(NodeLocatedEventArgs eventArgs)
{
NodeLocated?.Invoke(eventArgs);
}
public void OnEnvOutput(InfoType type, string value)
{
EnvOutput?.Invoke(type, value);
}
}
/// <summary>
/// 轻量级流程环境实现
/// </summary>
public class LightweightFlowEnvironment : IFlowEnvironment
{
public void WriteLine(InfoType type, string message, InfoClass @class = InfoClass.Trivial)
{
Console.WriteLine(message);
}
public ISereinIOC IOC => throw new NotImplementedException();
public IFlowEdit FlowEdit => throw new NotImplementedException();
public IFlowControl FlowControl => throw new NotImplementedException();
public IFlowEnvironmentEvent Event => throw new NotImplementedException();
public string EnvName => throw new NotImplementedException();
public string ProjectFileLocation => throw new NotImplementedException();
public bool IsGlobalInterrupt => throw new NotImplementedException();
public bool IsControlRemoteEnv => throw new NotImplementedException();
public InfoClass InfoClass { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public RunState FlowState { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public IFlowEnvironment CurrentEnv => throw new NotImplementedException();
public UIContextOperation UIContextOperation => throw new NotImplementedException();
public Task<(bool, RemoteMsgUtil)> ConnectRemoteEnv(string addres, int port, string token)
{
throw new NotImplementedException();
}
public void ExitRemoteEnv()
{
throw new NotImplementedException();
}
public Task<FlowEnvInfo> GetEnvInfoAsync()
{
throw new NotImplementedException();
}
public Task<SereinProjectData> GetProjectInfoAsync()
{
throw new NotImplementedException();
}
public void LoadAllNativeLibraryOfRuning(string path, bool isRecurrence = true)
{
throw new NotImplementedException();
}
public void LoadLibrary(string dllPath)
{
throw new NotImplementedException();
}
public bool LoadNativeLibraryOfRuning(string file)
{
throw new NotImplementedException();
}
public void LoadProject(string filePath)
{
throw new NotImplementedException();
}
public Task LoadProjetAsync(string filePath)
{
throw new NotImplementedException();
}
public Task NotificationNodeValueChangeAsync(string nodeGuid, string path, object value)
{
throw new NotImplementedException();
}
public void SaveProject()
{
throw new NotImplementedException();
}
public void SetUIContextOperation(UIContextOperation uiContextOperation)
{
throw new NotImplementedException();
}
public Task StartRemoteServerAsync(int port = 7525)
{
throw new NotImplementedException();
}
public void StopRemoteServer()
{
throw new NotImplementedException();
}
public bool TryGetDelegateDetails(string assemblyName, string methodName, out DelegateDetails del)
{
throw new NotImplementedException();
}
public bool TryGetMethodDetailsInfo(string assemblyName, string methodName, out MethodDetailsInfo mdInfo)
{
throw new NotImplementedException();
}
public bool TryGetNodeModel(string nodeGuid, out IFlowNode nodeModel)
{
throw new NotImplementedException();
}
public bool TryUnloadLibrary(string assemblyFullName)
{
throw new NotImplementedException();
}
}
}

View File

@@ -208,14 +208,106 @@ namespace Serein.Library
return pd;
}
public async Task<object> ToMethodArgData(IDynamicContext context)
{
// 1. 从缓存获取
if (context.TryGetParamsTempData(NodeModel.Guid, Index, out var data))
return data;
// 2. 特定快捷类型
if (typeof(IFlowEnvironment).IsAssignableFrom(DataType)) return NodeModel.Env;
if (typeof(IDynamicContext).IsAssignableFrom(DataType)) return context;
if (typeof(IFlowNode).IsAssignableFrom(DataType)) return NodeModel;
// 3. 显式常量参数
if (IsExplicitData && !DataValue.StartsWith("@", StringComparison.OrdinalIgnoreCase))
return DataValue.ToConvert(DataType);
/* // 4. 枚举绑定类型
if (ExplicitType is not null && ExplicitType.IsEnum && DataType != ExplicitType)
{
var resultEnum = Enum.Parse(ExplicitType, DataValue);
var boundType = EnumHelper.GetBoundValue(ExplicitType, resultEnum, attr => attr.Value) as Type;
if (boundType != null)
return NodeModel.Env.IOC.CreateObject(boundType);
}*/
// 5. 来自其他节点
object inputParameter = null;
var env = NodeModel.Env;
if (ArgDataSourceType == ConnectionArgSourceType.GetPreviousNodeData)
{
var prevNode = context.GetPreviousNode(NodeModel.Guid);
inputParameter = prevNode != null ? context.GetFlowData(prevNode)?.Value : null;
}
else
{
var prevNodeGuid = context.GetPreviousNode(NodeModel.Guid);
if (!env.TryGetNodeModel(ArgDataSourceNodeGuid, out var sourceNode))
throw new Exception($"[arg{Index}] 节点[{ArgDataSourceNodeGuid}]不存在");
if (sourceNode.IsPublic
&& env.TryGetNodeModel(prevNodeGuid, out var prevNode)
&& prevNode.ControlType == NodeControlType.FlowCall
&& env.TryGetNodeModel(context.GetPreviousNode(NodeModel.Guid), out var sourceNodeTemp)
)
sourceNode = sourceNodeTemp;
if (ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeData)
inputParameter = context.GetFlowData(sourceNode.Guid)?.Value;
else if (ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeDataOfInvoke)
inputParameter = (await sourceNode.ExecutingAsync(context, CancellationToken.None)).Value;
else
throw new Exception("无效的 ArgDataSourceType");
}
// 6. 表达式处理
if (IsExplicitData && DataValue.StartsWith("@", StringComparison.OrdinalIgnoreCase))
{
var lower = DataValue.ToLowerInvariant();
if (lower.StartsWith("@get") || lower.StartsWith("@dtc") || lower.StartsWith("@data"))
{
inputParameter = SerinExpressionEvaluator.Evaluate(DataValue, inputParameter, out _);
}
}
// 7. 类型转换
if (!DataType.IsValueType && inputParameter is null)
throw new Exception($"[arg{Index}] 参数不能为null");
if (DataType == typeof(string))
return inputParameter.ToString();
var actualType = inputParameter.GetType();
if (DataType.IsAssignableFrom(actualType))
return inputParameter;
if (DataType.IsSubclassOf(actualType))
return ObjectConvertHelper.ConvertParentToChild(inputParameter, DataType);
throw new Exception($"[arg{Index}] 类型不匹配:目标类型为 {DataType},实际类型为 {actualType}");
}
/// <summary>
/// 转为方法入参数据
/// </summary>
/// <returns></returns>
public async ValueTask<object> ToMethodArgData(IDynamicContext context)
public async Task<object> ToMethodArgData2(IDynamicContext context)
{
var nodeModel = NodeModel;
var env = nodeModel.Env;
#region
if (context.TryGetParamsTempData(NodeModel.Guid, Index, out var data))
{
return data;
}
#endregion
#region
// 返回运行环境
if (typeof(IFlowEnvironment).IsAssignableFrom(DataType))
@@ -236,8 +328,13 @@ namespace Serein.Library
if (IsExplicitData && !DataValue.StartsWith("@", StringComparison.OrdinalIgnoreCase))
{
return DataValue.ToConvert(DataType); // 并非表达式,同时是显式设置的参数
}
}
#endregion
#region -
if (ExplicitType is not null && ExplicitType.IsEnum && DataType != ExplicitType)
{
@@ -258,7 +355,7 @@ namespace Serein.Library
if (ArgDataSourceType == ConnectionArgSourceType.GetPreviousNodeData)
{
var previousNode = context.GetPreviousNode(nodeModel);
var previousNode = context.GetPreviousNode(nodeModel.Guid);
if (previousNode is null)
{
inputParameter = null;
@@ -281,8 +378,9 @@ namespace Serein.Library
// 如果是公开的节点,需要判断上下文调用中是否存在流程接口节点
if (argSourceNodeModel.IsPublic)
{
var pn = context.GetPreviousNode(NodeModel);
if(pn.ControlType == NodeControlType.FlowCall)
var pnGuid = context.GetPreviousNode(NodeModel.Guid);
var pn = env.TryGetNodeModel(pnGuid, out var tmpNode) ? tmpNode : null;
if (pn.ControlType == NodeControlType.FlowCall)
{
argSourceNodeModel = pn;
}
@@ -290,7 +388,7 @@ namespace Serein.Library
if (ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeData)
{
var flowData = context.GetFlowData(argSourceNodeModel);
var flowData = context.GetFlowData(argSourceNodeModel.Guid);
if(flowData is null)
{
inputParameter = null;