mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-12 04:29:25 +08:00
完善节点图的代码生成
This commit is contained in:
397
NodeFlow/Services/FlowLibraryService.cs
Normal file
397
NodeFlow/Services/FlowLibraryService.cs
Normal file
@@ -0,0 +1,397 @@
|
||||
using Serein.Library;
|
||||
using Serein.Library.Api;
|
||||
using Serein.Library.FlowNode;
|
||||
using Serein.Library.Utils;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Loader;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Serein.NodeFlow.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// 管理加载在运行环境中的外部程序集
|
||||
/// </summary>
|
||||
public class FlowLibraryService
|
||||
{
|
||||
public FlowLibraryService(IFlowEnvironment flowEnvironment)
|
||||
{
|
||||
this.flowEnvironment = flowEnvironment;
|
||||
}
|
||||
|
||||
private readonly IFlowEnvironment flowEnvironment;
|
||||
|
||||
/// <summary>
|
||||
/// 缓存所有加载了的程序集
|
||||
/// </summary>
|
||||
private readonly ConcurrentDictionary<string, FlowLibrary> _myFlowLibrarys = new ConcurrentDictionary<string, FlowLibrary>();
|
||||
|
||||
/// <summary>
|
||||
/// 加载类库
|
||||
/// </summary>
|
||||
/// <param name="libraryfilePath"></param>
|
||||
/// <returns></returns>
|
||||
public (NodeLibraryInfo, List<MethodDetailsInfo>) LoadLibraryOfPath(string libraryfilePath)
|
||||
{
|
||||
|
||||
var dir = Path.GetDirectoryName(libraryfilePath); // 获取目录路径
|
||||
var sereinFlowBaseLibraryPath = Path.Combine(dir, SereinBaseLibrary);// 每个类库下面至少需要有“Serein.Library.dll”类库依赖
|
||||
if (!Path.Exists(sereinFlowBaseLibraryPath))
|
||||
{
|
||||
throw new Exception($"从文件加载DLL失败,目标文件夹不存在{SereinBaseLibrary}文件" );
|
||||
}
|
||||
|
||||
var flowAlc = new FlowLibraryAssemblyContext(sereinFlowBaseLibraryPath, Path.GetFileName(libraryfilePath));
|
||||
var assembly = flowAlc.LoadFromAssemblyPath(libraryfilePath); // 加载指定路径的程序集
|
||||
|
||||
var flowLibrary = new FlowLibrary(assembly);
|
||||
try
|
||||
{
|
||||
var reulst = LoadFlowLibrary(flowLibrary);
|
||||
return reulst;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
flowAlc?.Unload(); // 卸载程序集
|
||||
flowAlc = null;
|
||||
GC.Collect(); // 强制触发GC确保卸载成功
|
||||
GC.WaitForPendingFinalizers();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载类库
|
||||
/// </summary>
|
||||
/// <param name="flowLibrary"></param>
|
||||
/// <returns></returns>
|
||||
public (NodeLibraryInfo, List<MethodDetailsInfo>) LoadLibraryOfPath(FlowLibrary flowLibrary)
|
||||
{
|
||||
return LoadFlowLibrary(flowLibrary);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 卸载类库
|
||||
/// </summary>
|
||||
/// <param name="assemblyName"></param>
|
||||
/// <returns></returns>
|
||||
public bool UnloadLibrary(string assemblyName)
|
||||
{
|
||||
if (_myFlowLibrarys.Remove(assemblyName, out var flowLibrary))
|
||||
{
|
||||
try
|
||||
{
|
||||
flowLibrary.Upload(); // 尝试卸载
|
||||
flowLibrary = null;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.ERROR, $"尝试卸载程序集[{assemblyName}]发生错误:{ex}");
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取方法描述
|
||||
/// </summary>
|
||||
/// <param name="assemblyName">程序集名称</param>
|
||||
/// <param name="methodName">方法名称</param>
|
||||
/// <param name="md">返回的方法描述</param>
|
||||
/// <returns>是否获取成功</returns>
|
||||
public bool TryGetMethodInfo(string assemblyName, string methodName, [MaybeNullWhen(false)] out MethodInfo methodInfo)
|
||||
{
|
||||
if (string.IsNullOrEmpty(assemblyName) || string.IsNullOrEmpty(methodName))
|
||||
{
|
||||
methodInfo = null;
|
||||
return false;
|
||||
}
|
||||
if (_myFlowLibrarys.TryGetValue(assemblyName, out var flowLibrary)
|
||||
&& flowLibrary.MethodInfos.TryGetValue(methodName, out methodInfo))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
methodInfo = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取方法描述
|
||||
/// </summary>
|
||||
/// <param name="assemblyName">程序集名称</param>
|
||||
/// <param name="methodName">方法名称</param>
|
||||
/// <param name="md">返回的方法描述</param>
|
||||
/// <returns>是否获取成功</returns>
|
||||
public bool TryGetMethodDetails(string assemblyName, string methodName, [MaybeNullWhen(false)] out MethodDetails md)
|
||||
{
|
||||
if (_myFlowLibrarys.TryGetValue(assemblyName, out var flowLibrary)
|
||||
&& flowLibrary.MethodDetailss.TryGetValue(methodName, out md))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
md = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取方法调用的委托
|
||||
/// </summary>
|
||||
/// <param name="assemblyName">程序集名称</param>
|
||||
/// <param name="methodName">方法名称</param>
|
||||
/// <param name="dd">返回的委托调用封装类</param>
|
||||
/// <returns>是否获取成功</returns>
|
||||
public bool TryGetDelegateDetails(string assemblyName, string methodName, [MaybeNullWhen(false)] out DelegateDetails dd)
|
||||
{
|
||||
if (_myFlowLibrarys.TryGetValue(assemblyName, out var flowLibrary)
|
||||
&& flowLibrary.DelegateDetailss.TryGetValue(methodName, out dd))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
dd = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取(初始化/加载时/退出后)相应的节点方法
|
||||
/// </summary>
|
||||
/// <param name="nodeType"></param>
|
||||
/// <returns></returns>
|
||||
public List<MethodDetails> GetMdsOnFlowStart(NodeType nodeType)
|
||||
{
|
||||
List<MethodDetails> mds = [];
|
||||
|
||||
foreach (var library in _myFlowLibrarys.Values)
|
||||
{
|
||||
var t_mds = library.MethodDetailss.Values.Where(it => it.MethodDynamicType == nodeType).ToList();
|
||||
mds.AddRange(t_mds);
|
||||
}
|
||||
return mds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取流程启动时在不同时间点需要自动实例化的类型
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Dictionary<RegisterSequence, List<Type>> GetaAutoRegisterType()
|
||||
{
|
||||
Dictionary<RegisterSequence, List<Type>> rsTypes = new Dictionary<RegisterSequence, List<Type>>();
|
||||
foreach (var library in _myFlowLibrarys.Values)
|
||||
{
|
||||
foreach (var kv in library.RegisterTypes)
|
||||
{
|
||||
var @class = kv.Key;
|
||||
var type = kv.Value;
|
||||
if (!rsTypes.TryGetValue(@class, out var tmpTypes))
|
||||
{
|
||||
tmpTypes = new List<Type>();
|
||||
rsTypes.Add(@class, tmpTypes);
|
||||
}
|
||||
tmpTypes.AddRange(type);
|
||||
}
|
||||
}
|
||||
return rsTypes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取某个程序集下的所有方法信息,用于保存项目时调用
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<MethodDetails> GetLibraryMdsOfAssmbly(string assemblyName)
|
||||
{
|
||||
if (_myFlowLibrarys.TryGetValue(assemblyName, out var flowLibrary))
|
||||
{
|
||||
return flowLibrary.MethodDetailss.Values.ToList();
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有方法信息,用于保存项目时调用
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<LibraryMds> GetAllLibraryMds()
|
||||
{
|
||||
List<LibraryMds> mds = new List<LibraryMds>();
|
||||
foreach (FlowLibrary library in _myFlowLibrarys.Values)
|
||||
{
|
||||
var tmp = new LibraryMds
|
||||
{
|
||||
AssemblyName = library.FullName,
|
||||
Mds = library.MethodDetailss.Values.Select(md => md.ToInfo()).ToArray()
|
||||
};
|
||||
mds.Add(tmp);
|
||||
}
|
||||
return mds;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 序列化当前项目的依赖信息、节点信息,用于远程登录的场景,需要将依赖信息从本地(受控端)发送到远程(主控端)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<NodeLibraryInfo> GetAllLibraryInfo()
|
||||
{
|
||||
return _myFlowLibrarys.Values.Select(library => library.ToInfo()).ToList();
|
||||
}
|
||||
|
||||
|
||||
#region 功能性方法
|
||||
|
||||
/// <summary>
|
||||
/// 基础依赖
|
||||
/// </summary>
|
||||
public readonly static string SereinBaseLibrary = $"{nameof(Serein)}.{nameof(Library)}.dll";
|
||||
|
||||
//private (NodeLibraryInfo, List<MethodDetailsInfo>) LoadDllNodeInfo(Assembly assembly)
|
||||
//{
|
||||
|
||||
// if (assembly.FullName?.ToString().Equals(typeof(IFlowEnvironment).Assembly.FullName?.ToString()) == true)
|
||||
// {
|
||||
|
||||
// // 加载基础依赖
|
||||
// return LoadAssembly(typeof(IFlowEnvironment).Assembly);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// var assembly_result = LoadAssembly(assembly);
|
||||
// return assembly_result;
|
||||
// }
|
||||
// catch (Exception)
|
||||
// {
|
||||
// return (null,[]);
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
//}
|
||||
|
||||
|
||||
|
||||
private (NodeLibraryInfo, List<MethodDetailsInfo>) LoadFlowLibrary(FlowLibrary flowLibrary)
|
||||
{
|
||||
var assembly = flowLibrary.Assembly;
|
||||
if (assembly.FullName?.ToString().Equals(typeof(IFlowEnvironment).Assembly.FullName?.ToString()) == true)
|
||||
{
|
||||
// 加载基础依赖
|
||||
flowLibrary = new FlowLibrary(typeof(IFlowEnvironment).Assembly);
|
||||
}
|
||||
|
||||
var assmblyName = assembly.GetName().Name;
|
||||
if (!string.IsNullOrEmpty(assmblyName) && _myFlowLibrarys.ContainsKey(assmblyName))
|
||||
{
|
||||
throw new Exception($"程序集[{assembly.GetName().FullName}]已经加载过!");
|
||||
}
|
||||
|
||||
var loadResult = flowLibrary.LoadAssembly(); // 加载程序集
|
||||
if (loadResult)
|
||||
{
|
||||
var assemblyName = assembly.GetName().Name;
|
||||
if (string.IsNullOrEmpty(assemblyName))
|
||||
{
|
||||
throw new Exception($"程序集[{assembly.GetName().FullName}]加载失败,没有程序集名称");
|
||||
}
|
||||
_myFlowLibrarys.TryAdd(assemblyName, flowLibrary);
|
||||
|
||||
List<MethodDetailsInfo> mdInfos = flowLibrary.MethodDetailss.Values.Select(md => md.ToInfo()).ToList();
|
||||
mdInfos.Sort((a, b) => string.Compare(a.MethodName, b.MethodName, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
(NodeLibraryInfo, List<MethodDetailsInfo>) result = (flowLibrary.ToInfo(), mdInfos);
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"程序集[{assembly.GetName().FullName}]加载失败");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 流程依赖加载
|
||||
/// </summary>
|
||||
public class FlowLibraryAssemblyContext : AssemblyLoadContext
|
||||
{
|
||||
private readonly AssemblyDependencyResolver _resolver;
|
||||
|
||||
/// <summary>
|
||||
/// 创建新的加载上下文
|
||||
/// </summary>
|
||||
/// <param name="sereinFlowLibraryPath">类库路径</param>
|
||||
/// <param name="name"></param>
|
||||
public FlowLibraryAssemblyContext(string sereinFlowLibraryPath, string name) : base(name, isCollectible: true)
|
||||
{
|
||||
_resolver = new AssemblyDependencyResolver(sereinFlowLibraryPath);
|
||||
}
|
||||
|
||||
protected override Assembly? Load(AssemblyName assemblyName)
|
||||
{
|
||||
string? assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);
|
||||
if (!string.IsNullOrEmpty(assemblyPath))
|
||||
{
|
||||
var assembly = Default.LoadFromAssemblyPath(assemblyPath);
|
||||
//var assembly = LoadFromAssemblyPath(assemblyPath);
|
||||
return assembly;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Default.Assemblies.FirstOrDefault(x => x.FullName == assemblyName.FullName);
|
||||
}
|
||||
|
||||
// return null;
|
||||
|
||||
// 构建依赖项的路径
|
||||
//string assemblyPath = Path.Combine(AppContext.BaseDirectory, assemblyName.Name + ".dll");
|
||||
//if (File.Exists(assemblyPath))
|
||||
//{
|
||||
// return LoadFromAssemblyPath(assemblyPath);
|
||||
//}
|
||||
//assemblyPath = Path.Combine(filePath, assemblyName.Name + ".dll");
|
||||
//if (File.Exists(assemblyPath))
|
||||
//{
|
||||
// return LoadFromAssemblyPath(assemblyPath);
|
||||
//}
|
||||
|
||||
//return null; // 如果没有找到,返回 null
|
||||
}
|
||||
}
|
||||
//public static class PluginAssemblyContextExtensions
|
||||
//{
|
||||
|
||||
// public static Assembly FromAssemblyPath(this AssemblyLoadContext context, string path)
|
||||
// {
|
||||
|
||||
// return context.LoadFromAssemblyPath(path);
|
||||
|
||||
// }
|
||||
|
||||
//}
|
||||
}
|
||||
@@ -1,9 +1,14 @@
|
||||
using Serein.Library;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Serein.Library;
|
||||
using Serein.Library.Api;
|
||||
using Serein.Library.Utils;
|
||||
using Serein.NodeFlow.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
@@ -16,10 +21,12 @@ namespace Serein.NodeFlow.Services
|
||||
public class FlowModelService
|
||||
{
|
||||
private readonly IFlowEnvironment environment;
|
||||
private readonly FlowLibraryService flowLibraryService;
|
||||
|
||||
public FlowModelService(IFlowEnvironment environment)
|
||||
public FlowModelService(IFlowEnvironment environment, FlowLibraryService flowLibraryService )
|
||||
{
|
||||
this.environment = environment;
|
||||
this.flowLibraryService = flowLibraryService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -114,53 +121,646 @@ namespace Serein.NodeFlow.Services
|
||||
return flowCanvasDetails.Nodes.Count > 0;
|
||||
}
|
||||
|
||||
#region 代码生成
|
||||
|
||||
public void ToCsharpCoreFile()
|
||||
public string ToCsharpCoreFile()
|
||||
{
|
||||
// TODO: 实现将流程模型转换为C# Core文件的逻辑
|
||||
// 遍历每个画布
|
||||
int canvas_index = 0;
|
||||
|
||||
#region 生成类和方法
|
||||
#if false
|
||||
HashSet<Type> assemblyFlowClasss = new HashSet<Type>(); // 用于创建依赖注入项
|
||||
assemblyFlowClasss.Add(typeof(IFlowCallTree)); // 调用树
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
foreach (var canvas in FlowCanvass.Values)
|
||||
{
|
||||
if (canvas.StartNode is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
int flowTemplateId = canvas_index++;
|
||||
string flowTemplateClassName = $"FlowTemplate{flowTemplateId}";
|
||||
string flowTemplateClassName = $"FlowTemplate_{canvas.Guid.Replace("-", "")}";
|
||||
|
||||
HashSet<Type> flowClasss = new HashSet<Type>();
|
||||
|
||||
flowClasss.Add(typeof(IFlowCallTree)); // 调用树
|
||||
// 收集程序集信息
|
||||
foreach (var node in canvas.Nodes)
|
||||
{
|
||||
var instanceType = node.MethodDetails.ActingInstanceType;
|
||||
if(instanceType is not null)
|
||||
{
|
||||
flowClasss.Add(instanceType);
|
||||
assemblyFlowClasss.Add(instanceType);
|
||||
if (instanceType is not null)
|
||||
{
|
||||
flowClasss.Add(instanceType);
|
||||
assemblyFlowClasss.Add(instanceType);
|
||||
}
|
||||
}
|
||||
|
||||
// 生成方法信息
|
||||
stringBuilder.AppendCode(0, $"public class {flowTemplateClassName}");
|
||||
stringBuilder.AppendCode(0, $"{{");
|
||||
|
||||
// 构造函数及依赖注入字段
|
||||
GenerateCtor(stringBuilder, flowTemplateClassName, flowClasss);
|
||||
//GenerateNodeIndexLookup(stringBuilder, flowTemplateClassName, );
|
||||
GenerateInitMethod(stringBuilder);
|
||||
GenerateCallTree(stringBuilder, canvas);
|
||||
|
||||
// 节点生成方法信息
|
||||
foreach (var node in canvas.Nodes)
|
||||
{
|
||||
var instanceType = node.MethodDetails.ActingInstanceType;
|
||||
var returnType = node.MethodDetails.ReturnType;
|
||||
var methodName = node.MethodDetails.MethodAnotherName;
|
||||
|
||||
GenerateMethod(stringBuilder, node);
|
||||
}
|
||||
stringBuilder.AppendCode(0, $"}}");
|
||||
|
||||
}
|
||||
#else
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
HashSet<Type> assemblyFlowClasss = new HashSet<Type>(); // 用于创建依赖注入项
|
||||
assemblyFlowClasss.Add(typeof(IFlowCallTree)); // 调用树
|
||||
var flowNodes = NodeModels.Values.ToArray();
|
||||
// 收集程序集信息
|
||||
foreach (var node in flowNodes)
|
||||
{
|
||||
var instanceType = node.MethodDetails.ActingInstanceType;
|
||||
if (instanceType is not null)
|
||||
{
|
||||
assemblyFlowClasss.Add(instanceType);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
string flowTemplateClassName = $"FlowTemplate"; // 类名
|
||||
stringBuilder.AppendCode(0, $"public class {flowTemplateClassName} : global::{typeof(IFlowCallTree).FullName}");
|
||||
stringBuilder.AppendCode(0, $"{{");
|
||||
GenerateCtor(stringBuilder, flowTemplateClassName, assemblyFlowClasss); // 生成构造方法
|
||||
GenerateInitMethod(stringBuilder); // 生成初始化方法
|
||||
GenerateCallTree(stringBuilder, flowNodes); // 生成调用树
|
||||
GenerateNodeIndexLookup(stringBuilder, flowTemplateClassName, flowNodes); // 初始化节点缓存
|
||||
foreach (var node in flowNodes)
|
||||
{
|
||||
GenerateMethod(stringBuilder, node); // 生成每个节点的方法
|
||||
}
|
||||
stringBuilder.AppendCode(0, $"}}");
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
|
||||
var instanceTypeFullName = instanceType.FullName;
|
||||
var returnTypeFullName = returnType == typeof(void) ? "void" : returnType.FullName;
|
||||
|
||||
string methodContext = $"private {returnTypeFullName} NodeMethod_{methodName}({nameof(IDynamicContext)} context)";
|
||||
SereinEnv.WriteLine(InfoType.INFO, methodContext);
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成构造函数代码
|
||||
/// </summary>
|
||||
/// <param name="sb"></param>
|
||||
/// <param name="className"></param>
|
||||
/// <param name="assemblyFlowClasss"></param>
|
||||
/// <returns></returns>
|
||||
private void GenerateCtor(StringBuilder sb, string className, HashSet<Type> assemblyFlowClasss)
|
||||
{
|
||||
if (assemblyFlowClasss.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var instanceTypes = assemblyFlowClasss.Where(x => !IsStaticClass(x)).ToArray();
|
||||
|
||||
for (int index = 0; index < instanceTypes.Length; index++)
|
||||
{
|
||||
var type = instanceTypes[index];
|
||||
var ctor_parms_name = GetCamelCase(type);
|
||||
sb.AppendCode(2, $"private readonly global::{type.FullName} {ctor_parms_name};");
|
||||
}
|
||||
|
||||
sb.AppendLine();
|
||||
|
||||
sb.AppendCode(2, $"public {className}(", false);
|
||||
for (int index = 0; index < instanceTypes.Length; index++)
|
||||
{
|
||||
var type = instanceTypes[index];
|
||||
var ctor_parms_name = GetCamelCase(type);
|
||||
sb.Append($"global::{type.FullName} {ctor_parms_name}{(index < instanceTypes.Length - 1 ? "," : "")}");
|
||||
}
|
||||
sb.AppendCode(0, $")");
|
||||
sb.AppendCode(2, $"{{");
|
||||
for (int index = 0; index < instanceTypes.Length; index++)
|
||||
{
|
||||
var type = instanceTypes[index];
|
||||
var ctor_parms_name = GetCamelCase(type);
|
||||
sb.AppendCode(3, $"this.{ctor_parms_name} = {ctor_parms_name};");
|
||||
}
|
||||
sb.AppendLine();
|
||||
sb.AppendCode(3, $"Init();"); // 初始化调用树
|
||||
sb.AppendCode(2, $"}}");
|
||||
sb.AppendLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成方法调用逻辑
|
||||
/// </summary>
|
||||
/// <param name="sb_main"></param>
|
||||
/// <param name="flowNode"></param>
|
||||
/// <exception cref="Exception"></exception>
|
||||
private void GenerateMethod(StringBuilder sb_main, IFlowNode flowNode)
|
||||
{
|
||||
string? dynamicContextTypeName = typeof(IDynamicContext).FullName;
|
||||
string? flowContext = nameof(flowContext);
|
||||
|
||||
if (flowNode.ControlType == NodeControlType.Action)
|
||||
{
|
||||
#region 生成 Action 节点类型的调用过程
|
||||
if (!flowLibraryService.TryGetMethodInfo(flowNode.MethodDetails.AssemblyName,
|
||||
flowNode.MethodDetails.MethodName,
|
||||
out var methodInfo) || methodInfo is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var isRootNode = flowNode.IsRoot();
|
||||
|
||||
var instanceType = flowNode.MethodDetails.ActingInstanceType;
|
||||
var returnType = methodInfo.ReturnType;
|
||||
|
||||
var instanceName = GetCamelCase(instanceType);// $"instance_{instanceType.Name}";
|
||||
|
||||
var instanceTypeFullName = instanceType.FullName;
|
||||
var returnTypeFullName = returnType == typeof(void) ? "void" : returnType.FullName;
|
||||
|
||||
#region 方法内部逻辑
|
||||
StringBuilder sb_invoke_login = new StringBuilder();
|
||||
if (flowNode.MethodDetails is null) return;
|
||||
var param = methodInfo.GetParameters();
|
||||
var md = flowNode.MethodDetails;
|
||||
var pds = flowNode.MethodDetails.ParameterDetailss;
|
||||
if (param is null) return;
|
||||
if (pds is null) return;
|
||||
|
||||
bool isGetPreviousNode = false;
|
||||
for (int index = 0; index < pds.Length; index++)
|
||||
{
|
||||
ParameterDetails? pd = pds[index];
|
||||
ParameterInfo parameterInfo = param[index];
|
||||
var paramtTypeFullName = parameterInfo.ParameterType.FullName;
|
||||
|
||||
if (pd.IsExplicitData)
|
||||
{
|
||||
// 只能是 数值、 文本、枚举, 才能作为显式参数
|
||||
if (parameterInfo.ParameterType.IsValueType)
|
||||
{
|
||||
if (parameterInfo.ParameterType.IsEnum)
|
||||
{
|
||||
sb_invoke_login.AppendCode(3, $"global::{paramtTypeFullName} value{index} = global::{paramtTypeFullName}.{pd.DataValue}; // 获取当前节点的上一节点数据");
|
||||
}
|
||||
else
|
||||
{
|
||||
var value = pd.DataValue.ToConvert(parameterInfo.ParameterType);
|
||||
sb_invoke_login.AppendCode(3, $"global::{paramtTypeFullName} value{index} = (global::{paramtTypeFullName}){value}; // 获取当前节点的上一节点数据");
|
||||
|
||||
}
|
||||
}
|
||||
else if (parameterInfo.ParameterType == typeof(string))
|
||||
{
|
||||
sb_invoke_login.AppendCode(3, $"global::{paramtTypeFullName} value{index} = \"{pd.DataValue}\"; // 获取当前节点的上一节点数据");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 处理表达式
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
#region 非显式设置的参数以正常方式获取
|
||||
if (pd.ArgDataSourceType == ConnectionArgSourceType.GetPreviousNodeData)
|
||||
{
|
||||
var previousNode = $"previousNode{index}";
|
||||
var valueType = pd.IsParams ? $"global::{pd.DataType.FullName}" : $"global::{paramtTypeFullName}";
|
||||
sb_invoke_login.AppendCode(3, $"global::System.String {previousNode} = {flowContext}.GetPreviousNode(\"{flowNode.Guid}\");"); // 获取运行时上一节点Guid
|
||||
sb_invoke_login.AppendCode(3, $"{valueType} value{index} = {previousNode} == null ? default : ({valueType}){flowContext}.{nameof(IDynamicContext.GetFlowData)}({previousNode}).Value; // 获取运行时上一节点的数据");
|
||||
}
|
||||
else if (pd.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeData)
|
||||
{
|
||||
if (this.TryGetNodeModel(pd.ArgDataSourceNodeGuid, out var otherNode))
|
||||
{
|
||||
var valueType = pd.IsParams ? $"global::{pd.DataType.FullName}" : $"global::{paramtTypeFullName}";
|
||||
var otherNodeReturnType = otherNode.MethodDetails.ReturnType;
|
||||
if (otherNodeReturnType == typeof(object))
|
||||
{
|
||||
sb_invoke_login.AppendCode(3, $"{valueType} value{index} = ({valueType}){flowContext}.{nameof(IDynamicContext.GetFlowData)}(\"{pd.ArgDataSourceNodeGuid}\").Value; // 获取指定节点的数据");
|
||||
}
|
||||
else if (pd.DataType.IsAssignableFrom(otherNodeReturnType))
|
||||
{
|
||||
sb_invoke_login.AppendCode(3, $"{valueType} value{index} = {flowContext}.{nameof(IDynamicContext.GetFlowData)}(\"{pd.ArgDataSourceNodeGuid}\").Value; // 获取指定节点的数据");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 获取的数据无法转换为目标方法入参类型
|
||||
throw new Exception("获取的数据无法转换为目标方法入参类型");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 指定了Guid,但项目中不存在对应的节点,需要抛出异常
|
||||
throw new Exception("指定了Guid,但项目中不存在对应的节点");
|
||||
}
|
||||
}
|
||||
else if (pd.ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeDataOfInvoke)
|
||||
{
|
||||
if (this.TryGetNodeModel(pd.ArgDataSourceNodeGuid, out var otherNode)) // 获取指定节点
|
||||
{
|
||||
var otherNodeReturnType = otherNode.MethodDetails.ReturnType;
|
||||
var valueType = pd.IsParams ? $"global::{pd.DataType.FullName}" : $"global::{otherNode.MethodDetails.ReturnType.FullName}";
|
||||
if (otherNodeReturnType == typeof(object))
|
||||
{
|
||||
sb_invoke_login.AppendCode(3, $"{valueType} value{index} = ({valueType}){flowContext}.{nameof(IDynamicContext.GetFlowData)}(\"{pd.ArgDataSourceNodeGuid}\").Value; // 获取指定节点的数据");
|
||||
}
|
||||
else if (pd.DataType.IsAssignableFrom(otherNodeReturnType))
|
||||
{
|
||||
sb_invoke_login.AppendCode(3, $"{valueType} value{index} = {GetNodeMethodName(otherNode)}({flowContext}); // 获取指定节点的数据");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 获取的数据无法转换为目标方法入参类型
|
||||
throw new Exception("获取的数据无法转换为目标方法入参类型");
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// 指定了Guid,但项目中不存在对应的节点,需要抛出异常
|
||||
throw new Exception("指定了Guid,但项目中不存在对应的节点");
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (methodInfo.ReturnType == typeof(void))
|
||||
{
|
||||
if (methodInfo.IsStatic)
|
||||
{
|
||||
sb_invoke_login.AppendCode(3, $"global::{instanceType}.{methodInfo.Name}(", false);
|
||||
for (int index = 0; index < pds.Length; index++)
|
||||
{
|
||||
sb_invoke_login.Append($"{(index == 0 ? "" : ",")}value{index}");
|
||||
}
|
||||
sb_invoke_login.AppendCode(0, $"); // 调用方法 {md.MethodAnotherName}");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb_invoke_login.AppendCode(3, $"{instanceName}.{methodInfo.Name}(", false);
|
||||
for (int index = 0; index < pds.Length; index++)
|
||||
{
|
||||
sb_invoke_login.Append($"{(index == 0 ? "" : ",")}value{index}");
|
||||
}
|
||||
sb_invoke_login.AppendCode(0, $"); // 调用方法 {md.MethodAnotherName}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (methodInfo.IsStatic)
|
||||
{
|
||||
sb_invoke_login.AppendCode(3, $"var result = global::{instanceType}.{methodInfo.Name}(", false);
|
||||
for (int index = 0; index < pds.Length; index++)
|
||||
{
|
||||
sb_invoke_login.Append($"{(index == 0 ? "" : ",")}value{index}");
|
||||
}
|
||||
sb_invoke_login.AppendCode(0, $"); // 调用方法 {md.MethodAnotherName}");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb_invoke_login.AppendCode(3, $"var result = {instanceName}.{methodInfo.Name}(", false);
|
||||
for (int index = 0; index < pds.Length; index++)
|
||||
{
|
||||
sb_invoke_login.Append($"{(index == 0 ? "" : ",")}value{index}");
|
||||
}
|
||||
sb_invoke_login.AppendCode(0, $"); // 调用方法 {md.MethodAnotherName}");
|
||||
}
|
||||
|
||||
sb_invoke_login.AppendCode(3, $"{flowContext}.{nameof(IDynamicContext.AddOrUpdate)}(\"{flowNode.Guid}\", result);", false);
|
||||
//sb_invoke_login.AppendCode(3, $"return result;", false);
|
||||
}
|
||||
#endregion
|
||||
|
||||
// global::{returnTypeFullName}
|
||||
|
||||
sb_main.AppendCode(2, $"[Description(\"{instanceTypeFullName}.{methodInfo.Name}\")]");
|
||||
sb_main.AppendCode(2, $"public void {GetNodeMethodName(flowNode)}(global::{dynamicContextTypeName} {flowContext})");
|
||||
sb_main.AppendCode(2, $"{{");
|
||||
sb_main.AppendCode(0, sb_invoke_login.ToString());
|
||||
sb_main.AppendCode(2, $"}}"); // 方法结束
|
||||
sb_main.AppendLine(); // 方法结束
|
||||
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
else if (flowNode.ControlType == NodeControlType.Flipflop)
|
||||
{
|
||||
}
|
||||
else if (flowNode.ControlType == NodeControlType.Script)
|
||||
{
|
||||
}
|
||||
else if (flowNode.ControlType == NodeControlType.UI)
|
||||
{
|
||||
}
|
||||
else if (flowNode.ControlType == NodeControlType.ExpCondition)
|
||||
{
|
||||
|
||||
}
|
||||
else if (flowNode.ControlType == NodeControlType.ExpOp)
|
||||
{
|
||||
}
|
||||
|
||||
return;
|
||||
throw new Exception("无法为该节点生成调用逻辑");
|
||||
}
|
||||
|
||||
private void GenerateInitMethod(StringBuilder sb)
|
||||
{
|
||||
sb.AppendCode(2, $"public void Init()");
|
||||
sb.AppendCode(2, $"{{");
|
||||
sb.AppendCode(3, $"{nameof(GenerateCallTree)}(); // 初始化调用树"); // 初始化调用树
|
||||
sb.AppendCode(2, $"}}");
|
||||
}
|
||||
|
||||
private void GenerateCallTree(StringBuilder sb, IFlowNode[] flowNodes)
|
||||
{
|
||||
// Get("0fa6985b-4b63-4499-80b2-76401669292d").AddChildNodeSucceed(Get("acdbe7ea-eb27-4a3e-9cc9-c48f642ee4f5"));
|
||||
|
||||
sb.AppendCode(2, $"private void {nameof(GenerateCallTree)}()");
|
||||
sb.AppendCode(2, $"{{");
|
||||
|
||||
foreach (var node in flowNodes)
|
||||
{
|
||||
var nodeMethod = GetNodeMethodName(node); // 节点对应的方法名称
|
||||
sb.AppendCode(3, $"Get(\"{node.Guid}\").SetAction({nodeMethod});");
|
||||
}
|
||||
|
||||
foreach (var node in flowNodes)
|
||||
{
|
||||
var nodeMethod = GetNodeMethodName(node); // 节点对应的方法名称
|
||||
var cts = NodeStaticConfig.ConnectionTypes;
|
||||
foreach (var ct in cts)
|
||||
{
|
||||
var childNodes = node.SuccessorNodes[ct];
|
||||
var AddChildNodeMethodName = ct switch
|
||||
{
|
||||
ConnectionInvokeType.IsSucceed => nameof(CallNode.AddChildNodeSucceed),
|
||||
ConnectionInvokeType.IsFail => nameof(CallNode.AddChildNodeFail),
|
||||
ConnectionInvokeType.IsError => nameof(CallNode.AddChildNodeError),
|
||||
ConnectionInvokeType.Upstream => nameof(CallNode.AddChildNodeUpstream),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(ct), ct, null)
|
||||
};
|
||||
foreach (var childNode in childNodes)
|
||||
{
|
||||
sb.AppendCode(3, $"Get(\"{node.Guid}\").{AddChildNodeMethodName}(Get(\"{childNode.Guid}\"));");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
sb.AppendCode(2, $"}}");
|
||||
sb.AppendLine();
|
||||
|
||||
/*string? dynamicContextTypeName = typeof(IDynamicContext).FullName;
|
||||
string? flowContext = nameof(flowContext);
|
||||
var callTreeType = typeof(IFlowCallTree);
|
||||
var callTreeName = GetCamelCase(callTreeType);
|
||||
//var canvasGuid = flowCanvas.Guid;
|
||||
//var startNodeGuid = flowCanvas.StartNode.Guid;
|
||||
|
||||
sb.AppendCode(2, $"private void {nameof(GenerateCallTree)}()");
|
||||
sb.AppendCode(2, $"{{");
|
||||
//sb.AppendCode(3, $"global::{callTreeType.FullName} {callTreeName} = new global::{callTreeType.FullName}()\";");
|
||||
|
||||
// 注册节点
|
||||
*//* foreach (var node in flowCanvas.Nodes)
|
||||
{
|
||||
var nodeMethod = GetNodeMethodName(node);
|
||||
var call = $"{flowContext} => {nodeMethod}({flowContext})";
|
||||
sb.AppendCode(3, $"{callTreeName}.{nameof(FlowCallTree.AddCallNode)}(\"{node.Guid}\", {call});");
|
||||
}*//*
|
||||
|
||||
sb.AppendLine();
|
||||
foreach (var node in flowNodes)
|
||||
{
|
||||
var nodeMethod = GetNodeMethodName(node);
|
||||
var cts = NodeStaticConfig.ConnectionTypes;
|
||||
foreach (var ct in cts)
|
||||
{
|
||||
var childNodes = node.SuccessorNodes[ct];
|
||||
var addType = ct switch
|
||||
{
|
||||
ConnectionInvokeType.IsSucceed => nameof(CallNode.AddChildNodeSucceed),
|
||||
ConnectionInvokeType.IsFail => nameof(CallNode.AddChildNodeFail),
|
||||
ConnectionInvokeType.IsError => nameof(CallNode.AddChildNodeError),
|
||||
ConnectionInvokeType.Upstream => nameof(CallNode.AddChildNodeUpstream),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(ct), ct, null)
|
||||
};
|
||||
foreach (var childNode in childNodes)
|
||||
{
|
||||
sb.AppendCode(3, $"{callTreeName}[\"{node.Guid}\"].{addType}(\"{childNode.Guid}\");");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
sb.AppendCode(2, $"}}");
|
||||
sb.AppendLine();*/
|
||||
}
|
||||
|
||||
private void GenerateNodeIndexLookup(StringBuilder sb, string className, IFlowNode[] flowNodes)
|
||||
{
|
||||
// 初始化Id
|
||||
nodeIdMap.Clear();
|
||||
for (int index = 0; index < flowNodes.Length; index++)
|
||||
{
|
||||
var flowNode = flowNodes[index];
|
||||
GetNodeId(flowNode);
|
||||
}
|
||||
|
||||
var valueArrayName = "_values";
|
||||
|
||||
// 生成 _values
|
||||
sb.AppendCode(2, $"private readonly static global::Serein.Library.CallNode[] {valueArrayName} = new global::Serein.Library.CallNode[{flowNodes.Length}];");
|
||||
|
||||
/*sb.AppendCode(2, $"private readonly static global::System.String[] _keys = new global::System.String[]");
|
||||
sb.AppendCode(2, $"{{");
|
||||
for (int index = 0; index < flowNodes.Length; index++)
|
||||
{
|
||||
var flowNode = flowNodes[index];
|
||||
sb.AppendCode(3, $"\"{flowNode.Guid}\", // {index} : {flowNode.MethodDetails.MethodName}");
|
||||
}
|
||||
sb.AppendCode(2, $"}};");*/
|
||||
|
||||
// 生成静态构造函数
|
||||
sb.AppendCode(2, $"static {className}()");
|
||||
sb.AppendCode(2, $"{{");
|
||||
for (int index = 0; index < flowNodes.Length; index++)
|
||||
{
|
||||
var flowNode = flowNodes[index];
|
||||
sb.AppendCode(3, $"{valueArrayName}[{index}] = new global::Serein.Library.CallNode(\"{flowNode.Guid}\"); // {index} : {flowNode.MethodDetails.MethodName}");
|
||||
}
|
||||
sb.AppendCode(2, $"}}");
|
||||
|
||||
// 初始化 Get 函数
|
||||
var nodeIndexName = "node_index";
|
||||
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};");
|
||||
sb.AppendCode(3, $"switch (key)");
|
||||
sb.AppendCode(3, $"{{");
|
||||
|
||||
for (int index = 0; index < flowNodes.Length; index++)
|
||||
{
|
||||
var flowNode = flowNodes[index];
|
||||
sb.AppendCode(4, $"case \"{flowNode.Guid}\":");
|
||||
sb.AppendCode(5, $"{nodeIndexName} = {index};");
|
||||
sb.AppendCode(5, $"break;");
|
||||
}
|
||||
sb.AppendCode(4, $"default:");
|
||||
sb.AppendCode(4, $"{nodeIndexName} = -1;");
|
||||
sb.AppendCode(5, $"break;");
|
||||
sb.AppendCode(3, $"}}");
|
||||
sb.AppendCode(3, $"return {valueArrayName}[{nodeIndexName}];");
|
||||
sb.AppendCode(2, $"}}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成方法名称
|
||||
/// </summary>
|
||||
/// <param name="flowNode"></param>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private string GetNodeMethodName(IFlowNode flowNode)
|
||||
{
|
||||
/*if (!flowLibraryService.TryGetMethodInfo(flowNode.MethodDetails.AssemblyName,
|
||||
flowNode.MethodDetails.MethodName,
|
||||
out var methodInfo))
|
||||
{
|
||||
throw new Exception();
|
||||
}*/
|
||||
var guid = flowNode.Guid;
|
||||
var tmp = guid.Replace("-", "");
|
||||
var methodName = $"FlowMethod_{tmp}";
|
||||
return methodName;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private bool IsStaticClass(Type type)
|
||||
{
|
||||
return type.IsAbstract && type.IsSealed && type.IsClass;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private string GetCamelCase(Type type)
|
||||
{
|
||||
if (type == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(type));
|
||||
}
|
||||
|
||||
// 获取类型名称(不包括命名空间)
|
||||
string typeName = type.Name;
|
||||
|
||||
if (string.IsNullOrEmpty(typeName))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
// 处理泛型类型(去掉后面的`N)
|
||||
int indexOfBacktick = typeName.IndexOf('`');
|
||||
if (indexOfBacktick > 0)
|
||||
{
|
||||
typeName = typeName.Substring(0, indexOfBacktick);
|
||||
}
|
||||
|
||||
// 如果是接口且以"I"开头,去掉第一个字母
|
||||
if (type.IsInterface && typeName.Length > 1 && typeName[0] == 'I' && char.IsUpper(typeName[1]))
|
||||
{
|
||||
typeName = typeName.Substring(1);
|
||||
}
|
||||
|
||||
// 转换为驼峰命名法:首字母小写,其余不变
|
||||
if (typeName.Length > 0)
|
||||
{
|
||||
return char.ToLowerInvariant(typeName[0]) + typeName.Substring(1);
|
||||
}
|
||||
|
||||
return typeName;
|
||||
}
|
||||
|
||||
private Dictionary<IFlowNode, int> nodeIdMap = new Dictionary<IFlowNode, int>();
|
||||
private int GetNodeId(IFlowNode flowNode)
|
||||
{
|
||||
if (nodeIdMap.ContainsKey(flowNode))
|
||||
{
|
||||
return nodeIdMap[flowNode];
|
||||
}
|
||||
else
|
||||
{
|
||||
lock (nodeIdMap)
|
||||
{
|
||||
int id = nodeIdMap.Count + 1; // 从1开始计数
|
||||
nodeIdMap[flowNode] = id;
|
||||
return id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* /// <summary>
|
||||
/// 生成方法名称
|
||||
/// </summary>
|
||||
/// <param name="flowNode"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
private string GetNodeMethodName(IFlowNode flowNode)
|
||||
{
|
||||
return $"FlowMethod_{flowNode.Guid.Remove('-')}";
|
||||
|
||||
if (flowNode.ControlType == NodeControlType.Action)
|
||||
{
|
||||
if (!flowLibraryService.TryGetMethodInfo(flowNode.MethodDetails.AssemblyName,
|
||||
flowNode.MethodDetails.MethodName,
|
||||
out var methodInfo))
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
return $"FlowMethod_{nameof(NodeControlType.Action)}_{methodInfo.Name}";
|
||||
}
|
||||
else if (flowNode.ControlType == NodeControlType.Flipflop)
|
||||
{
|
||||
if (!flowLibraryService.TryGetMethodInfo(flowNode.MethodDetails.AssemblyName,
|
||||
flowNode.MethodDetails.MethodName,
|
||||
out var methodInfo))
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
return $"FlowMethod_{nameof(NodeControlType.Flipflop)}_{methodInfo.Name}";
|
||||
|
||||
}
|
||||
else if (flowNode.ControlType == NodeControlType.Script)
|
||||
{
|
||||
return $"FlowMethod_{flowNode.Guid.Remove('-')}";
|
||||
}
|
||||
else if (flowNode.ControlType == NodeControlType.UI)
|
||||
{
|
||||
|
||||
}
|
||||
else if (flowNode.ControlType == NodeControlType.ExpCondition)
|
||||
{
|
||||
|
||||
}
|
||||
else if (flowNode.ControlType == NodeControlType.ExpOp)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("无法为该节点生成方法名称");
|
||||
}
|
||||
}*/
|
||||
@@ -268,14 +268,16 @@ namespace Serein.NodeFlow.Services
|
||||
/// </summary>
|
||||
/// <param name="startNode"></param>
|
||||
/// <returns></returns>
|
||||
public async Task StartFlowInSelectNodeAsync(IFlowNode startNode)
|
||||
public async Task<FlowResult> StartFlowInSelectNodeAsync(IFlowNode startNode)
|
||||
{
|
||||
var pool = WorkOptions.FlowContextPool;
|
||||
var context = pool.Allocate();
|
||||
var token = WorkOptions.CancellationTokenSource.Token;
|
||||
var result = await startNode.StartFlowAsync(context, token); // 开始运行时从选定节点开始运行
|
||||
|
||||
context.Reset();
|
||||
pool.Free(context);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -342,7 +344,7 @@ namespace Serein.NodeFlow.Services
|
||||
{
|
||||
var context = pool.Allocate(); // 启动全局触发器时新建上下文
|
||||
var newFlowData = await singleFlipFlopNode.ExecutingAsync(context, singleToken); // 获取触发器等待Task
|
||||
context.AddOrUpdate(singleFlipFlopNode.Guid, newFlowData);
|
||||
context.AddOrUpdateFlowData(singleFlipFlopNode.Guid, newFlowData);
|
||||
if (context.NextOrientation == ConnectionInvokeType.None)
|
||||
{
|
||||
continue;
|
||||
|
||||
Reference in New Issue
Block a user