mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-15 14:06:37 +08:00
先想到这吧
This commit is contained in:
@@ -99,17 +99,22 @@ namespace Serein.NodeFlow.Base
|
||||
Stack<NodeModelBase> stack = new Stack<NodeModelBase>();
|
||||
stack.Push(this);
|
||||
var cts = context.Env.IOC.Get<CancellationTokenSource>(FlowStarter.FlipFlopCtsName);
|
||||
while (stack.Count > 0 && !cts.IsCancellationRequested) // 循环中直到栈为空才会退出循环
|
||||
while (stack.Count > 0 ) // 循环中直到栈为空才会退出循环
|
||||
{
|
||||
if(cts is not null)
|
||||
{
|
||||
if (cts.IsCancellationRequested)
|
||||
break;
|
||||
}
|
||||
// 节点执行异常时跳过执行
|
||||
|
||||
// 从栈中弹出一个节点作为当前节点进行处理
|
||||
var currentNode = stack.Pop();
|
||||
|
||||
// 设置方法执行的对象
|
||||
if (currentNode.MethodDetails?.ActingInstance == null && currentNode.MethodDetails?.ActingInstanceType is not null)
|
||||
if (currentNode.MethodDetails?.ActingInstance is not null && currentNode.MethodDetails?.ActingInstanceType is not null)
|
||||
{
|
||||
currentNode.MethodDetails.ActingInstance ??= context.Env.IOC.GetOrRegisterInstantiate(currentNode.MethodDetails.ActingInstanceType);
|
||||
currentNode.MethodDetails.ActingInstance = context.Env.IOC.GetOrRegisterInstantiate(currentNode.MethodDetails.ActingInstanceType);
|
||||
}
|
||||
|
||||
#region 执行相关
|
||||
@@ -134,7 +139,7 @@ namespace Serein.NodeFlow.Base
|
||||
|
||||
// 执行当前节点
|
||||
object? newFlowData = await currentNode.ExecutingAsync(context);
|
||||
if (cts == null || cts.IsCancellationRequested || currentNode.NextOrientation == ConnectionType.None)
|
||||
if (cts is null || cts.IsCancellationRequested || currentNode.NextOrientation == ConnectionType.None)
|
||||
{
|
||||
// 不再执行
|
||||
break;
|
||||
@@ -316,7 +321,7 @@ namespace Serein.NodeFlow.Base
|
||||
Type t when t.IsEnum => Enum.Parse(ed.DataType, ed.DataValue),// 需要枚举
|
||||
Type t when t.IsArray => (inputParameter as Array)?.Cast<object>().ToList(),
|
||||
Type t when t.IsGenericType && t.GetGenericTypeDefinition() == typeof(List<>) => inputParameter,
|
||||
Type t when Nullable.GetUnderlyingType(t) != null => inputParameter == null ? null : Convert.ChangeType(inputParameter, Nullable.GetUnderlyingType(t)),
|
||||
Type t when Nullable.GetUnderlyingType(t) != null => inputParameter is null ? null : Convert.ChangeType(inputParameter, Nullable.GetUnderlyingType(t)),
|
||||
_ => inputParameter,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -322,11 +322,21 @@ namespace Serein.NodeFlow
|
||||
else
|
||||
{
|
||||
TryGetMethodDetails(nodeInfo.MethodName, out MethodDetails? methodDetails); // 加载项目时尝试获取方法信息
|
||||
methodDetails ??= new MethodDetails();
|
||||
if(controlType == NodeControlType.ExpOp || controlType == NodeControlType.ExpOp)
|
||||
{
|
||||
methodDetails ??= new MethodDetails();
|
||||
}
|
||||
if(methodDetails is null)
|
||||
{
|
||||
continue; // 节点对应的方法不存在于DLL中
|
||||
}
|
||||
|
||||
|
||||
var nodeModel = CreateNode(controlType, methodDetails);
|
||||
nodeModel.LoadInfo(nodeInfo); // 创建节点model
|
||||
if (nodeModel is null)
|
||||
{
|
||||
nodeInfo.Guid = string.Empty;
|
||||
continue;
|
||||
}
|
||||
TryAddNode(nodeModel);
|
||||
@@ -393,8 +403,8 @@ namespace Serein.NodeFlow
|
||||
|
||||
List<(ConnectionType, NodeModelBase[])> fromNodes = allToNodes.Where(info => info.guids.Length > 0)
|
||||
.Select(info => (info.connectionType,
|
||||
info.guids.Select(guid => Nodes[guid])
|
||||
.ToArray()))
|
||||
info.guids.Where(guid => Nodes.ContainsKey(guid)).Select(guid => Nodes[guid])
|
||||
.ToArray()))
|
||||
.ToList();
|
||||
// 遍历每种类型的节点分支(四种)
|
||||
foreach ((ConnectionType connectionType, NodeModelBase[] toNodes) item in fromNodes)
|
||||
@@ -841,7 +851,7 @@ namespace Serein.NodeFlow
|
||||
foreach (var item in scanTypes)
|
||||
{
|
||||
// 加载DLL,创建 MethodDetails、实例作用对象、委托方法
|
||||
var itemMethodDetails = MethodDetailsHelperTmp.GetList(item, false);
|
||||
var itemMethodDetails = MethodDetailsHelperTmp.GetList(item);
|
||||
methodDetails.AddRange(itemMethodDetails);
|
||||
//foreach (var md in itemMethodDetails)
|
||||
//{
|
||||
@@ -905,7 +915,7 @@ namespace Serein.NodeFlow
|
||||
_ => null
|
||||
};
|
||||
|
||||
if (nodeType == null)
|
||||
if (nodeType is null)
|
||||
{
|
||||
throw new Exception($"节点类型错误[{nodeControlType}]");
|
||||
}
|
||||
@@ -953,7 +963,7 @@ namespace Serein.NodeFlow
|
||||
/// <param name="connectionType">连接关系</param>
|
||||
private void ConnectNode(NodeModelBase fromNode, NodeModelBase toNode, ConnectionType connectionType)
|
||||
{
|
||||
if (fromNode == null || toNode == null || fromNode == toNode)
|
||||
if (fromNode is null || toNode is null || fromNode == toNode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -308,10 +308,9 @@ namespace Serein.NodeFlow
|
||||
{
|
||||
|
||||
var context = new DynamicContext(env); // 启动全局触发器时新建上下文
|
||||
try
|
||||
while (!_flipFlopCts.IsCancellationRequested)
|
||||
{
|
||||
|
||||
while (!_flipFlopCts.IsCancellationRequested)
|
||||
try
|
||||
{
|
||||
var newFlowData = await singleFlipFlopNode.ExecutingAsync(context); // 获取触发器等待Task
|
||||
await NodeModelBase.RefreshFlowDataAndExpInterrupt(context, singleFlipFlopNode, newFlowData); // 全局触发器触发后刷新该触发器的节点数据
|
||||
@@ -321,7 +320,7 @@ namespace Serein.NodeFlow
|
||||
for (int i = nextNodes.Count - 1; i >= 0 && !_flipFlopCts.IsCancellationRequested; i--)
|
||||
{
|
||||
// 筛选出启用的节点
|
||||
if (nextNodes[i].DebugSetting.IsEnable)
|
||||
if (nextNodes[i].DebugSetting.IsEnable)
|
||||
{
|
||||
nextNodes[i].PreviousNode = singleFlipFlopNode;
|
||||
if (nextNodes[i].DebugSetting.InterruptClass != InterruptClass.None) // 执行触发前
|
||||
@@ -333,14 +332,12 @@ namespace Serein.NodeFlow
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await Console.Out.WriteLineAsync(ex.ToString());
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await Console.Out.WriteLineAsync(ex.ToString());
|
||||
}
|
||||
|
||||
|
||||
//MethodDetails md = singleFlipFlopNode.MethodDetails;
|
||||
//var del = md.MethodDelegate;
|
||||
|
||||
@@ -32,12 +32,8 @@ namespace Serein.NodeFlow.Model
|
||||
}
|
||||
internal override NodeInfo ToInfo()
|
||||
{
|
||||
if (MethodDetails == null) return null;
|
||||
if (MethodDetails is null) return null;
|
||||
|
||||
//var trueNodes = SucceedBranch.Select(item => item.Guid); // 真分支
|
||||
//var falseNodes = FailBranch.Select(item => item.Guid);// 假分支
|
||||
//var upstreamNodes = UpstreamBranch.Select(item => item.Guid);// 上游分支
|
||||
//var errorNodes = ErrorBranch.Select(item => item.Guid);// 异常分支
|
||||
var trueNodes = SuccessorNodes[ConnectionType.IsSucceed].Select(item => item.Guid); // 真分支
|
||||
var falseNodes = SuccessorNodes[ConnectionType.IsFail].Select(item => item.Guid);// 假分支
|
||||
var errorNodes = SuccessorNodes[ConnectionType.IsError].Select(item => item.Guid);// 异常分支
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace Serein.NodeFlow.Model
|
||||
{
|
||||
0 => ((Func<object, Task<IFlipflopContext>>)del).Invoke(md.ActingInstance),
|
||||
_ => ((Func<object, object?[]?, Task<IFlipflopContext>>)del).Invoke(md.ActingInstance, GetParameters(context, this, md)), // 执行流程中的触发器方法时获取入参参数
|
||||
};
|
||||
};
|
||||
|
||||
IFlipflopContext flipflopContext = (await flipflopTask) ?? throw new FlipflopException("没有返回上下文");
|
||||
NextOrientation = flipflopContext.State.ToContentType();
|
||||
|
||||
@@ -15,16 +15,16 @@ public static class MethodDetailsHelperTmp
|
||||
/// <param name="serviceContainer"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public static List<MethodDetails> GetList(Type type, bool isNetFramework)
|
||||
public static List<MethodDetails> GetList(Type type)
|
||||
{
|
||||
var methodDetailsDictionary = new List<MethodDetails>();
|
||||
var assemblyName = type.Assembly.GetName().Name;
|
||||
var methods = GetMethodsToProcess(type, isNetFramework);
|
||||
var methods = GetMethodsToProcess(type);
|
||||
|
||||
foreach (var method in methods)
|
||||
{
|
||||
|
||||
var methodDetails = CreateMethodDetails(type, method, assemblyName, isNetFramework);
|
||||
var methodDetails = CreateMethodDetails(type, method, assemblyName);
|
||||
methodDetailsDictionary.Add(methodDetails);
|
||||
}
|
||||
|
||||
@@ -33,26 +33,16 @@ public static class MethodDetailsHelperTmp
|
||||
/// <summary>
|
||||
/// 获取处理方法
|
||||
/// </summary>
|
||||
private static IEnumerable<MethodInfo> GetMethodsToProcess(Type type, bool isNetFramework)
|
||||
private static IEnumerable<MethodInfo> GetMethodsToProcess(Type type)
|
||||
{
|
||||
if (isNetFramework)
|
||||
{
|
||||
|
||||
return type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
|
||||
return type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
|
||||
.Where(m => m.GetCustomAttribute<NodeActionAttribute>()?.Scan == true);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
return type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
|
||||
.Where(m => m.GetCustomAttribute<NodeActionAttribute>()?.Scan == true);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 创建方法信息
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private static MethodDetails CreateMethodDetails(Type type, MethodInfo method, string assemblyName, bool isNetFramework)
|
||||
private static MethodDetails CreateMethodDetails(Type type, MethodInfo method, string assemblyName)
|
||||
{
|
||||
|
||||
var methodName = method.Name;
|
||||
@@ -98,18 +88,31 @@ public static class MethodDetailsHelperTmp
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取参数信息
|
||||
/// </summary>
|
||||
/// <param name="parameters"></param>
|
||||
/// <returns></returns>
|
||||
private static ExplicitData[] GetExplicitDataOfParameters(ParameterInfo[] parameters)
|
||||
{
|
||||
|
||||
return parameters.Select((it, index) =>
|
||||
{
|
||||
//Console.WriteLine($"{it.Name}-{it.HasDefaultValue}-{it.DefaultValue}");
|
||||
string explicitTypeName = GetExplicitTypeName(it.ParameterType);
|
||||
var items = GetExplicitItems(it.ParameterType, explicitTypeName);
|
||||
Type paremType;
|
||||
//var attribute = it.ParameterType.GetCustomAttribute<EnumConvertorAttribute>();
|
||||
//if (attribute is not null && attribute.Enum.IsEnum)
|
||||
//{
|
||||
// // 存在选择器
|
||||
// paremType = attribute.Enum;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// paremType = it.ParameterType;
|
||||
//}
|
||||
paremType = it.ParameterType;
|
||||
string explicitTypeName = GetExplicitTypeName(paremType);
|
||||
var items = GetExplicitItems(paremType, explicitTypeName);
|
||||
if ("Bool".Equals(explicitTypeName)) explicitTypeName = "Select"; // 布尔值 转为 可选类型
|
||||
|
||||
|
||||
|
||||
return new ExplicitData
|
||||
{
|
||||
IsExplicitData = it.HasDefaultValue,
|
||||
@@ -127,6 +130,11 @@ public static class MethodDetailsHelperTmp
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断使用输入器还是选择器
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
private static string GetExplicitTypeName(Type type)
|
||||
{
|
||||
return type switch
|
||||
@@ -140,15 +148,22 @@ public static class MethodDetailsHelperTmp
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取参数列表选项
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="explicitTypeName"></param>
|
||||
/// <returns></returns>
|
||||
private static IEnumerable<string> GetExplicitItems(Type type, string explicitTypeName)
|
||||
{
|
||||
return explicitTypeName switch
|
||||
IEnumerable<string> items = explicitTypeName switch
|
||||
{
|
||||
"Select" => Enum.GetNames(type),
|
||||
"Bool" => ["True", "False"],
|
||||
_ => []
|
||||
};
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
private static Delegate GenerateMethodDelegate(Type type, MethodInfo methodInfo, ParameterInfo[] parameters, Type returnType)
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace Serein.NodeFlow.Tool.SereinExpression.Resolver
|
||||
foreach (var member in members)
|
||||
{
|
||||
|
||||
if (obj == null) return null;
|
||||
if (obj is null) return null;
|
||||
|
||||
Type type = obj.GetType();
|
||||
PropertyInfo? propertyInfo = type.GetProperty(member);
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace Serein.NodeFlow.Tool.SereinExpression
|
||||
string[] members = memberPath[1..].Split('.');
|
||||
foreach (var member in members)
|
||||
{
|
||||
if (obj == null) return null;
|
||||
if (obj is null) return null;
|
||||
Type type = obj.GetType();
|
||||
PropertyInfo? propertyInfo = type.GetProperty(member);
|
||||
FieldInfo? fieldInfo = type.GetField(member);
|
||||
|
||||
@@ -99,7 +99,7 @@ namespace Serein.NodeFlow.Tool.SereinExpression
|
||||
.ToArray();
|
||||
|
||||
var method = target.GetType().GetMethod(methodName);
|
||||
if (method == null)
|
||||
if (method is null)
|
||||
{
|
||||
throw new ArgumentException($"Method {methodName} not found on target.");
|
||||
}
|
||||
@@ -125,7 +125,7 @@ namespace Serein.NodeFlow.Tool.SereinExpression
|
||||
foreach (var member in members)
|
||||
{
|
||||
|
||||
if (target == null) return null;
|
||||
if (target is null) return null;
|
||||
|
||||
|
||||
var property = target.GetType().GetProperty(member);
|
||||
|
||||
Reference in New Issue
Block a user