使用emit代替表达式树构造委托。

内置了websocket server与相应的导航功能,可在实例工程中找到相应的实现。
This commit is contained in:
fengjiayi
2024-10-10 10:45:53 +08:00
parent 0bab770f0a
commit d1b9a3f28f
43 changed files with 1953 additions and 392 deletions

View File

@@ -197,49 +197,69 @@ namespace Serein.NodeFlow.Base
{
throw new Exception($"节点{this.Guid}不存在方法信息请检查是否需要重写节点的ExecutingAsync");
}
if (!context.Env.TryGetDelegate(md.MethodName, out var del))
if (!context.Env.TryGetDelegateDetails(md.MethodName, out var dd))
{
throw new Exception($"节点{this.Guid}不存在对应委托");
}
md.ActingInstance ??= context.Env.IOC.Get(md.ActingInstanceType);
object instance = md.ActingInstance;
bool haveParameter = md.ExplicitDatas.Length > 0;
bool haveResult = md.ReturnType != typeof(void);
Type? taskResult = null;
bool isTask = md.ReturnType is not null && MethodDetailsHelperTmp.IsGenericTask(md.ReturnType, out taskResult);
bool isTaskHaveResult = taskResult is not null;
object? result;
//bool haveParameter = md.ExplicitDatas.Length > 0;
//bool haveResult = md.ReturnType != typeof(void);
// Type? taskResult = null;
//bool isTask = md.ReturnType is not null && MethodDetailsHelper.IsGenericTask(md.ReturnType, out taskResult);
//bool isTaskHaveResult = taskResult is not null;
object? result = null;
//Console.WriteLine($"(isTask, isTaskHaveResult):{(isTask, isTaskHaveResult)}");
try
{
// Action/Func([方法作用的实例],[可能的参数值],[可能的返回值])
object?[]? parameters = GetParameters(context, this, md);
if (isTask)
object?[]? args = GetParameters(context, this, md);
var delType = dd.EmitMethodType;
var del = dd.EmitDelegate;
if (delType == EmitHelper.EmitMethodType.HasResultTask && del is Func<object, object?[]?, Task<object?>> hasResultTask)
{
// 异步方法因为返回了Task所以排除Action<>委托的可能)
result = (haveParameter, isTaskHaveResult) switch
{
(false, false) => await ExecutionAsync((Func<object, Task>)del, instance), // 调用节点方法,返回方法传回类型
(true, false) => await ExecutionAsync((Func<object, object?[]?, Task>)del, instance, parameters), // 调用节点方法,获取入参参数,返回方法返回类型
(false, true) => await ExecutionAsync((Func<object, Task<object?>>)del, instance), // 调用节点方法,返回方法传回类型
(true, true) => await ExecutionAsync((Func<object, object?[]?, Task<object?>>)del, instance, parameters), // 调用节点方法,获取入参参数,返回方法返回类型
};
result = await hasResultTask(instance, args);
}
else if (delType == EmitHelper.EmitMethodType.Task && del is Func<object, object?[]?, Task> task)
{
await task.Invoke(instance, args);
result = null;
}
else if (delType == EmitHelper.EmitMethodType.Func && del is Func<object, object?[]?, object?> func)
{
result = func.Invoke(instance, args);
}
else
{
// 非异步方法
result = (haveParameter, haveResult) switch
{
(false, false) => Execution((Action<object>)del, instance), // 调用节点方法返回null
(true, false) => Execution((Action<object, object?[]?>)del, instance, parameters), // 调用节点方法返回null
(false, true) => Execution((Func<object, object?>)del, instance), // 调用节点方法,返回方法传回类型
(true, true) => Execution((Func<object, object?[]?, object?>)del, instance, parameters), // 调用节点方法,获取入参参数,返回方法返回类型
};
throw new NotImplementedException("构造委托无法正确调用");
}
//if (isTask)
//{
// // 异步方法因为返回了Task所以排除Action<>委托的可能)
// result = (haveParameter, isTaskHaveResult) switch
// {
// (false, false) => await ExecutionAsync((Func<object, Task>)del, instance), // 调用节点方法,返回方法传回类型
// (true, false) => await ExecutionAsync((Func<object, object?[]?, Task>)del, instance, parameters), // 调用节点方法,获取入参参数,返回方法返回类型
// (false, true) => await ExecutionAsync((Func<object, Task<object?>>)del, instance), // 调用节点方法,返回方法传回类型
// (true, true) => await ExecutionAsync((Func<object, object?[]?, Task<object?>>)del, instance, parameters), // 调用节点方法,获取入参参数,返回方法返回类型
// };
//}
//else
//{
// // 非异步方法
// result = (haveParameter, haveResult) switch
// {
// (false, false) => Execution((Action<object>)del, instance), // 调用节点方法返回null
// (true, false) => Execution((Action<object, object?[]?>)del, instance, parameters), // 调用节点方法返回null
// (false, true) => Execution((Func<object, object?>)del, instance), // 调用节点方法,返回方法传回类型
// (true, true) => Execution((Func<object, object?[]?, object?>)del, instance, parameters), // 调用节点方法,获取入参参数,返回方法返回类型
// };
//}
NextOrientation = ConnectionType.IsSucceed;
return result;
}

View File

@@ -184,14 +184,15 @@ namespace Serein.NodeFlow
/// 存放触发器节点(运行时全部调用)
/// </summary>
private List<SingleFlipflopNode> FlipflopNodes { get; } = [];
private List<Type> AutoRegisterTypes { get; } = [];
private Dictionary<RegisterSequence,List<Type>> AutoRegisterTypes { get; } = [];
/// <summary>
/// 存放委托
///
/// md.Methodname - delegate
/// </summary>
private ConcurrentDictionary<string, Delegate> MethodDelegates { get; } = [];
private ConcurrentDictionary<string, DelegateDetails> MethodDelegates { get; } = [];
/// <summary>
/// 起始节点私有属性
@@ -256,11 +257,11 @@ namespace Serein.NodeFlow
}
this.IOC.Reset(); // 开始运行时清空ioc中注册的实例
this.IOC.CustomRegisterInstance(typeof(IFlowEnvironment).FullName,this);
foreach (var type in AutoRegisterTypes)
{
this.IOC.Register(type);
}
await flowStarter.RunAsync(this, nodes, initMethods, loadMethods, exitMethods);
await flowStarter.RunAsync(this, nodes, AutoRegisterTypes, initMethods, loadMethods, exitMethods);
if (flowStarter?.FlipFlopState == RunState.NoStart)
{
@@ -694,16 +695,16 @@ namespace Serein.NodeFlow
}
}
public bool TryGetDelegate(string methodName, out Delegate? del)
public bool TryGetDelegateDetails(string methodName, out DelegateDetails? delegateDetails)
{
if (!string.IsNullOrEmpty(methodName) && MethodDelegates.TryGetValue(methodName, out del))
if (!string.IsNullOrEmpty(methodName) && MethodDelegates.TryGetValue(methodName, out delegateDetails))
{
return del != null;
return delegateDetails != null;
}
else
{
del = null;
delegateDetails = null;
return false;
}
}
@@ -939,7 +940,16 @@ namespace Serein.NodeFlow
{
MethodDetailss.Add(nodeLibrary, mdlist);
NodeLibrarys.Add(nodeLibrary);
AutoRegisterTypes.AddRange(registerTypes);
foreach(var kv in registerTypes)
{
if (!AutoRegisterTypes.TryGetValue(kv.Key, out var types))
{
types = new List<Type>();
AutoRegisterTypes.Add(kv.Key, types);
}
types.AddRange(kv.Value);
}
OnDllLoad?.Invoke(new LoadDllEventArgs(nodeLibrary, mdlist)); // 通知UI创建dll面板显示
}
@@ -947,16 +957,35 @@ namespace Serein.NodeFlow
}
private (NodeLibrary?, List<Type> ,List<MethodDetails>) LoadAssembly(string dllPath)
private (NodeLibrary?, Dictionary<RegisterSequence, List<Type>>, List<MethodDetails>) LoadAssembly(string dllPath)
{
try
{
Assembly assembly = Assembly.LoadFrom(dllPath); // 加载DLL文件
Type[] types = assembly.GetTypes(); // 获取程序集中的所有类型
List<Type> autoRegisterTypes = assembly.GetTypes().Where(t => t.GetCustomAttribute<AutoRegisterAttribute>() is not null).ToList();
Dictionary<RegisterSequence, List<Type>> autoRegisterTypes = new Dictionary<RegisterSequence, List<Type>>();
foreach (Type type in types)
{
var autoRegisterAttribute = type.GetCustomAttribute<AutoRegisterAttribute>();
if (autoRegisterAttribute is not null)
{
if(!autoRegisterTypes.TryGetValue(autoRegisterAttribute.Class,out var valus))
{
valus = new List<Type>();
autoRegisterTypes.Add(autoRegisterAttribute.Class, valus);
}
valus.Add(type);
}
}
List<(Type, string)> scanTypes = assembly.GetTypes().Select(t => {
//Dictionary<Sequence, Type> autoRegisterTypes = assembly.GetTypes().Where(t => t.GetCustomAttribute<AutoRegisterAttribute>() is not null).ToList();
List<(Type, string)> scanTypes = types.Select(t => {
if (t.GetCustomAttribute<DynamicFlowAttribute>() is DynamicFlowAttribute dynamicFlowAttribute
&& dynamicFlowAttribute.Scan == true)
{
@@ -982,10 +1011,10 @@ namespace Serein.NodeFlow
{
continue;
}
var methods = MethodDetailsHelperTmp.GetMethodsToProcess(type);
var methods = MethodDetailsHelper.GetMethodsToProcess(type);
foreach(var method in methods)
{
(var md, var del) = MethodDetailsHelperTmp.CreateMethodDetails(type, method, assemblyName);
(var md, var del) = MethodDetailsHelper.CreateMethodDetails(type, method, assemblyName);
if(md is null || del is null)
{
Console.WriteLine($"无法加载方法信息:{assemblyName}-{type}-{method}");

View File

@@ -1,4 +1,5 @@
using Serein.Library.Api;
using Serein.Library.Attributes;
using Serein.Library.Core.NodeFlow;
using Serein.Library.Entity;
using Serein.Library.Enums;
@@ -109,6 +110,7 @@ namespace Serein.NodeFlow
/// <returns></returns>
public async Task RunAsync(IFlowEnvironment env,
List<NodeModelBase> nodes,
Dictionary<RegisterSequence, List<Type>> autoRegisterTypes,
List<MethodDetails> initMethods,
List<MethodDetails> loadingMethods,
List<MethodDetails> exitMethods)
@@ -150,6 +152,7 @@ namespace Serein.NodeFlow
#endregion
#region Ioc容器
// 清除节点使用的对象,筛选出需要初始化的方法描述
var thisRuningMds = new List<MethodDetails>();
thisRuningMds.AddRange(runNodeMd.Where(md => md?.ActingInstanceType is not null));
@@ -178,10 +181,7 @@ namespace Serein.NodeFlow
}
}
if (IsStopStart)
{
return;// 初始化类型后检查状态
}
if (IsStopStart) return;// 检查所有dll节点是否存在类型
env.IOC.Build(); // 流程启动前的初始化
@@ -219,25 +219,43 @@ namespace Serein.NodeFlow
#region IOC容器
if (autoRegisterTypes.TryGetValue(RegisterSequence.FlowInit, out var flowInitTypes))
{
foreach (var type in flowInitTypes)
{
env.IOC.Register(type); // 初始化前注册
}
}
Context.Env.IOC.Build(); // 绑定初始化时注册的类型
//object?[]? args = [Context];
foreach (var md in initMethods) // 初始化
{
if (!env.TryGetDelegate(md.MethodName, out var del))
if (!env.TryGetDelegateDetails(md.MethodName, out var dd))
{
throw new Exception("不存在对应委托");
}
((Action<object, object?[]?>)del).Invoke(md.ActingInstance, [Context]);
((Func<object, object[], object>)dd.EmitDelegate).Invoke(md.ActingInstance, [Context]);
}
Context.Env.IOC.Build(); // 绑定初始化时注册的类型
if(autoRegisterTypes.TryGetValue(RegisterSequence.FlowLoading,out var flowLoadingTypes))
{
foreach (var type in flowLoadingTypes)
{
env.IOC.Register(type); // 初始化前注册
}
}
Context.Env.IOC.Build(); // 绑定初始化时注册的类型
foreach (var md in loadingMethods) // 加载
{
//object?[]? data = [md.ActingInstance, args];
//md.MethodDelegate.DynamicInvoke(data);
if (!env.TryGetDelegate(md.MethodName, out var del))
if (!env.TryGetDelegateDetails(md.MethodName, out var dd))
{
throw new Exception("不存在对应委托");
}
((Action<object, object?[]?>)del).Invoke(md.ActingInstance, [Context]);
//((Action<object, object?[]?>)del).Invoke(md.ActingInstance, [Context]);
((Func<object, object[], object>)dd.EmitDelegate).Invoke(md.ActingInstance, [Context]);
}
Context.Env.IOC.Build(); // 预防有人在加载时才注册类型,再绑定一次
#endregion
@@ -245,17 +263,17 @@ namespace Serein.NodeFlow
#region 退
ExitAction = () =>
{
env.IOC.Run<WebServer>(web => {
env.IOC.Run<WebApiServer>(web => {
web?.Stop();
});
foreach (MethodDetails? md in exitMethods)
{
if (!env.TryGetDelegate(md.MethodName, out var del))
if (!env.TryGetDelegateDetails(md.MethodName, out var dd))
{
throw new Exception("不存在对应委托");
}
((Action<object, object?[]?>)del).Invoke(md.ActingInstance, [Context]);
((Func<object, object[], object>)dd.EmitDelegate).Invoke(md.ActingInstance, [Context]);
}
TerminateAllGlobalFlipflop();

View File

@@ -2,6 +2,7 @@
using Serein.Library.Entity;
using Serein.Library.Enums;
using Serein.Library.Ex;
using Serein.Library.Utils;
using Serein.NodeFlow.Base;
using static Serein.Library.Utils.ChannelFlowInterrupt;
@@ -32,7 +33,7 @@ namespace Serein.NodeFlow.Model
#endregion
MethodDetails md = MethodDetails;
if (!context.Env.TryGetDelegate(md.MethodName, out var del))
if (!context.Env.TryGetDelegateDetails(md.MethodName, out var dd))
{
throw new Exception("不存在对应委托");
}
@@ -40,37 +41,31 @@ namespace Serein.NodeFlow.Model
try
{
Task<IFlipflopContext> flipflopTask;
if (md.ExplicitDatas.Length == 0)
var args = GetParameters(context, this, md);
var delType = dd.EmitMethodType;
var del = dd.EmitDelegate;
if (delType == EmitHelper.EmitMethodType.HasResultTask && del is Func<object, object?[]?, Task<object>> hasResultTask)
{
if (del is Func<object, Task<IFlipflopContext>> function)
var flipflopTaskObj = await hasResultTask(instance, args);
if(flipflopTaskObj is IFlipflopContext flipflopContext)
{
flipflopTask = function.Invoke(md.ActingInstance);
NextOrientation = flipflopContext.State.ToContentType();
if (flipflopContext.TriggerData is null || flipflopContext.TriggerData.Type == Library.NodeFlow.Tool.TriggerType.Overtime)
{
throw new FlipflopException(base.MethodDetails.MethodName + "触发器超时触发。Guid" + base.Guid);
}
return flipflopContext.TriggerData.Value;
}
else
{
throw new FlipflopException("触发节点非预期的返回类型", true, FlipflopException.CancelClass.Flow);
throw new FlipflopException("触发节点返回了非预期的类型", true, FlipflopException.CancelClass.Flow);
}
}
else
{
var parameters = GetParameters(context, this, md);
if(del is Func<object, object?[]?, Task<IFlipflopContext>> function)
{
flipflopTask = function.Invoke(md.ActingInstance, parameters);
}
else
{
throw new FlipflopException("触发节点非预期的返回类型", true,FlipflopException.CancelClass.Flow);
}
throw new FlipflopException("触发器节点构造了非预期的委托", true, FlipflopException.CancelClass.Flow);
}
IFlipflopContext flipflopContext = (await flipflopTask) ?? throw new FlipflopException("没有返回上下文");
NextOrientation = flipflopContext.State.ToContentType();
if(flipflopContext.TriggerData is null || flipflopContext.TriggerData.Type == Library.NodeFlow.Tool.TriggerType.Overtime)
{
throw new FlipflopException(base.MethodDetails.MethodName + "触发器超时触发。Guid"+base.Guid);
}
return flipflopContext.TriggerData.Value;
}
catch (FlipflopException ex)
{

View File

@@ -22,6 +22,7 @@
<Compile Remove="MethodDetails.cs" />
<Compile Remove="Tool\Attribute.cs" />
<Compile Remove="Tool\DynamicTool.cs" />
<Compile Remove="Tool\ExpressionHelper.cs" />
<Compile Remove="Tool\NodeModelBaseFunc.cs" />
<Compile Remove="Tool\TcsSignal.cs" />
</ItemGroup>

View File

@@ -2,6 +2,7 @@
using Serein.Library.Attributes;
using Serein.Library.Core.NodeFlow;
using Serein.Library.Entity;
using Serein.Library.Utils;
using System;
using System.Collections.Concurrent;
using System.ComponentModel;
@@ -10,7 +11,7 @@ using System.Text.RegularExpressions;
namespace Serein.NodeFlow.Tool;
public static class MethodDetailsHelperTmp
public static class MethodDetailsHelper
{
/// <summary>
@@ -53,7 +54,7 @@ public static class MethodDetailsHelperTmp
/// 创建方法信息
/// </summary>
/// <returns></returns>
public static (MethodDetails?,Delegate?) CreateMethodDetails(Type type, MethodInfo method, string assemblyName)
public static (MethodDetails?, DelegateDetails?) CreateMethodDetails(Type type, MethodInfo method, string assemblyName)
{
var attribute = method.GetCustomAttribute<NodeActionAttribute>();
if(attribute is null)
@@ -64,12 +65,14 @@ public static class MethodDetailsHelperTmp
var dllTypeMethodName = $"{assemblyName}.{type.Name}.{method.Name}";
var explicitDataOfParameters = GetExplicitDataOfParameters(method.GetParameters());
//// 生成委托
var methodDelegate = GenerateMethodDelegate(type, // 方法所在的对象类型
method, // 方法信息
method.GetParameters(),// 方法参数
method.ReturnType);// 返回值
//// 通过表达式树生成委托
//var methodDelegate = GenerateMethodDelegate(type, // 方法所在的对象类型
// method, // 方法信息
// method.GetParameters(),// 方法参数
// method.ReturnType);// 返回值
//// 通过表达式树生成委托
var emitMethodType = EmitHelper.CreateDynamicMethod(method, out var methodDelegate);// 返回值
Type? returnType;
bool isTask = IsGenericTask(method.ReturnType, out var taskResult);
@@ -114,8 +117,8 @@ public static class MethodDetailsHelperTmp
ExplicitDatas = explicitDataOfParameters,
ReturnType = returnType,
};
return (md, methodDelegate);
var dd = new DelegateDetails( emitMethodType, methodDelegate) ;
return (md, dd);
}
@@ -276,52 +279,52 @@ public static class MethodDetailsHelperTmp
return items;
}
private static Delegate GenerateMethodDelegate(Type type, MethodInfo methodInfo, ParameterInfo[] parameters, Type returnType)
{
var parameterTypes = parameters.Select(p => p.ParameterType).ToArray();
var parameterCount = parameters.Length;
//private static Delegate GenerateMethodDelegate(Type type, MethodInfo methodInfo, ParameterInfo[] parameters, Type returnType)
//{
// var parameterTypes = parameters.Select(p => p.ParameterType).ToArray();
// var parameterCount = parameters.Length;
if (returnType == typeof(void))
{
if (parameterCount == 0)
{
// 无返回值,无参数
return ExpressionHelper.MethodCaller(type, methodInfo);
}
else
{
// 无返回值,有参数
return ExpressionHelper.MethodCaller(type, methodInfo, parameterTypes);
}
}
// else if (returnType == typeof(Task<FlipflopContext)) // 触发器
else if (FlipflopFunc.IsTaskOfFlipflop(returnType)) // 触发器
{
if (parameterCount == 0)
{
// 有返回值,无参数
return ExpressionHelper.MethodCallerAsync(type, methodInfo);
}
else
{
// 有返回值,有参数
return ExpressionHelper.MethodCallerAsync(type, methodInfo, parameterTypes);
}
}
else
{
if (parameterCount == 0)
{
// 有返回值,无参数
return ExpressionHelper.MethodCallerHaveResult(type, methodInfo);
}
else
{
// 有返回值,有参数
return ExpressionHelper.MethodCallerHaveResult(type, methodInfo, parameterTypes);
}
}
}
// if (returnType == typeof(void))
// {
// if (parameterCount == 0)
// {
// // 无返回值,无参数
// return ExpressionHelper.MethodCaller(type, methodInfo);
// }
// else
// {
// // 无返回值,有参数
// return ExpressionHelper.MethodCaller(type, methodInfo, parameterTypes);
// }
// }
// // else if (returnType == typeof(Task<FlipflopContext)) // 触发器
// else if (FlipflopFunc.IsTaskOfFlipflop(returnType)) // 触发器
// {
// if (parameterCount == 0)
// {
// // 有返回值,无参数
// return ExpressionHelper.MethodCallerAsync(type, methodInfo);
// }
// else
// {
// // 有返回值,有参数
// return ExpressionHelper.MethodCallerAsync(type, methodInfo, parameterTypes);
// }
// }
// else
// {
// if (parameterCount == 0)
// {
// // 有返回值,无参数
// return ExpressionHelper.MethodCallerHaveResult(type, methodInfo);
// }
// else
// {
// // 有返回值,有参数
// return ExpressionHelper.MethodCallerHaveResult(type, methodInfo, parameterTypes);
// }
// }
//}
}