mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-03 00:00:49 +08:00
通过Emit优化Script脚本的解释执行;出于后期更新的方向,暂时隐藏表达式节点、条件表达式节点、全局数据节点;流程图转c#代码新增对于Script脚本的支持,Script脚本现在可以原生导出为C#代码。
This commit is contained in:
@@ -11,41 +11,81 @@ using static Serein.Library.Utils.EmitHelper;
|
||||
namespace Serein.Library
|
||||
{
|
||||
/// <summary>
|
||||
/// Emit创建的委托描述,用于WebApi、WebSocket、NodeFlow动态调用方法的场景。
|
||||
/// 通过 Emit 创建委托,代替反射调用方法,实现高性能的动态调用。
|
||||
/// 一般情况下你无须内部细节,只需要调用 Invoke() 方法即可。
|
||||
/// </summary>
|
||||
public class DelegateDetails
|
||||
{
|
||||
private readonly EmitType emitType = EmitType.None;
|
||||
|
||||
/// <summary>
|
||||
/// 创建的委托类型
|
||||
/// </summary>
|
||||
public enum EmitType
|
||||
{
|
||||
/// <summary>
|
||||
/// 默认
|
||||
/// </summary>
|
||||
None,
|
||||
/// <summary>
|
||||
/// 方法调用
|
||||
/// </summary>
|
||||
MethodInvoke,
|
||||
/// <summary>
|
||||
/// 字段赋值
|
||||
/// </summary>
|
||||
FieldSetter,
|
||||
/// <summary>
|
||||
/// 字段取值
|
||||
/// </summary>
|
||||
FieldGetter,
|
||||
/// <summary>
|
||||
/// 属性赋值
|
||||
/// </summary>
|
||||
PropertySetter,
|
||||
/// <summary>
|
||||
/// 属性取值
|
||||
/// </summary>
|
||||
PropertyGetter,
|
||||
/// <summary>
|
||||
/// 集合取值
|
||||
/// </summary>
|
||||
CollectionGetter,
|
||||
/// <summary>
|
||||
/// 集合赋值
|
||||
/// </summary>
|
||||
CollectionSetter
|
||||
}
|
||||
|
||||
public enum GSType
|
||||
{
|
||||
Get,
|
||||
Set,
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 根据方法信息构建Emit委托
|
||||
/// </summary>
|
||||
/// <param name="methodInfo"></param>
|
||||
public DelegateDetails(MethodInfo methodInfo)
|
||||
{
|
||||
emitType = EmitType.MethodInvoke;
|
||||
var emitMethodType = EmitHelper.CreateDynamicMethod(methodInfo, out var emitDelegate);
|
||||
_emitMethodInfo = emitMethodType;
|
||||
_emitDelegate = emitDelegate;
|
||||
|
||||
SetFunc();
|
||||
}
|
||||
|
||||
|
||||
private void SetFunc()
|
||||
{
|
||||
methodType = _emitMethodInfo.EmitMethodType;
|
||||
if (_emitDelegate is Func<object, object[], Task<object>> hasResultTask)
|
||||
{
|
||||
this.hasResultTask = hasResultTask;
|
||||
funcType = 2;
|
||||
this.methodHasResultTask = hasResultTask;
|
||||
}
|
||||
else if (_emitDelegate is Func<object, object[], Task> task)
|
||||
{
|
||||
this.task = task;
|
||||
funcType = 1;
|
||||
this.methodTask = task;
|
||||
}
|
||||
else if (_emitDelegate is Func<object, object[], object> func)
|
||||
{
|
||||
this.func = func;
|
||||
funcType = 0;
|
||||
this.methodInvoke = func;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -54,9 +94,97 @@ namespace Serein.Library
|
||||
}
|
||||
|
||||
|
||||
public Func<object, object[], Task<object>> hasResultTask;
|
||||
public Func<object, object[], Task> task;
|
||||
public Func<object, object[], object> func;
|
||||
|
||||
/// <summary>
|
||||
/// 根据字段信息构建Emit取/赋值委托
|
||||
/// </summary>
|
||||
/// <param name="fieldInfo">字段信息</param>
|
||||
/// <param name="gsType">是否为 get,如果不是,则为 set</param>
|
||||
public DelegateDetails(FieldInfo fieldInfo, GSType gsType)
|
||||
{
|
||||
if (gsType == GSType.Get)
|
||||
{
|
||||
emitType = EmitType.FieldGetter;
|
||||
getter = EmitHelper.CreateFieldGetter(fieldInfo);
|
||||
|
||||
}
|
||||
else if (gsType == GSType.Set)
|
||||
{
|
||||
emitType = EmitType.FieldSetter;
|
||||
setter = EmitHelper.CreateFieldSetter(fieldInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException("错误的构建类型");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据字段信息构建Emit取/赋值委托
|
||||
/// </summary>
|
||||
/// <param name="propertyInfo">字段信息</param>
|
||||
/// <param name="gsType">是否为 get,如果不是,则为 set</param>
|
||||
public DelegateDetails(PropertyInfo propertyInfo, GSType gsType)
|
||||
{
|
||||
if (gsType == GSType.Get)
|
||||
{
|
||||
emitType = EmitType.PropertyGetter;
|
||||
getter = EmitHelper.CreatePropertyGetter(propertyInfo);
|
||||
|
||||
}
|
||||
else if (gsType == GSType.Set)
|
||||
{
|
||||
emitType = EmitType.PropertySetter;
|
||||
setter = EmitHelper.CreatePropertySetter(propertyInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException("错误的构建类型");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 目前提供了创建集合取值/赋值委托
|
||||
/// </summary>
|
||||
/// <param name="type">类型信息</param>
|
||||
/// <param name="gsType">操作类型</param>
|
||||
public DelegateDetails(Type type, EmitType emitType)
|
||||
{
|
||||
if (emitType == EmitType.CollectionSetter)
|
||||
{
|
||||
emitType = EmitType.CollectionSetter;
|
||||
collectionSetter = EmitHelper.CreateCollectionSetter(type);
|
||||
|
||||
}
|
||||
else if (emitType == EmitType.CollectionGetter)
|
||||
{
|
||||
emitType = EmitType.CollectionGetter;
|
||||
collectionGetter = EmitHelper.CreateCollectionGetter(type);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException("错误的构建类型");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private Func<object,object, object> collectionGetter= null;
|
||||
private Action<object,object, object> collectionSetter = null;
|
||||
|
||||
|
||||
private Func<object, object> getter = null;
|
||||
private Action<object, object> setter = null;
|
||||
|
||||
|
||||
private Func<object, object[], Task<object>> methodHasResultTask = null;
|
||||
private Func<object, object[], Task> methodTask = null;
|
||||
private Func<object, object[], object> methodInvoke = null;
|
||||
|
||||
|
||||
/*/// <summary>
|
||||
@@ -72,12 +200,9 @@ namespace Serein.Library
|
||||
|
||||
private Delegate _emitDelegate;
|
||||
private EmitMethodInfo _emitMethodInfo;
|
||||
/// <summary>
|
||||
/// 0是普通
|
||||
/// 1是异步无返回值
|
||||
/// 2是异步有返回值
|
||||
/// </summary>
|
||||
private int funcType;
|
||||
|
||||
|
||||
private EmitMethodType methodType;
|
||||
|
||||
/// <summary>
|
||||
/// 该Emit委托的相应信息
|
||||
@@ -96,50 +221,65 @@ namespace Serein.Library
|
||||
//public EmitMethodType EmitMethodType { get => _emitMethodType; }
|
||||
|
||||
|
||||
|
||||
public async Task<object> AutoInvokeAsync(object[] args)
|
||||
{
|
||||
if (_emitMethodInfo.IsStatic)
|
||||
{
|
||||
return await InvokeAsync(null, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
var obj = Activator.CreateInstance(_emitMethodInfo.DeclaringType);
|
||||
return await InvokeAsync(obj, args);
|
||||
}
|
||||
throw new Exception("Not static method");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <para>使用的实例必须能够正确调用该委托,传入的参数也必须符合方法入参信息。</para>
|
||||
/// </summary>
|
||||
/// <param name="instance">拥有符合委托签名的方法信息的实例</param>
|
||||
/// <param name="args">如果方法没有入参,也需要传入一个空数组</param>
|
||||
/// <returns>void方法自动返回null</returns>
|
||||
/// <param name="instance">拥有符合委托签名的实例</param>
|
||||
/// <param name="args">如果不需要入参,也需要传入一个空数组,而不能为 null</param>
|
||||
/// <returns>void方法、setter自动返回null</returns>
|
||||
public async Task<object> InvokeAsync(object instance, object[] args)
|
||||
{
|
||||
if (emitType == EmitType.MethodInvoke)
|
||||
{
|
||||
return await MethodInvoke(instance, args);
|
||||
}
|
||||
else if (emitType == EmitType.PropertyGetter || emitType == EmitType.FieldGetter)
|
||||
{
|
||||
return getter(instance);
|
||||
}
|
||||
else if (emitType == EmitType.PropertySetter || emitType == EmitType.FieldSetter)
|
||||
{
|
||||
setter(instance, args[0]);
|
||||
return null;
|
||||
}
|
||||
else if (emitType == EmitType.CollectionGetter)
|
||||
{
|
||||
return collectionGetter(instance, args[0]);
|
||||
}
|
||||
else if (emitType == EmitType.CollectionSetter)
|
||||
{
|
||||
collectionSetter(instance, args[0], args[1]);
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException("当前委托类型不支持 InvokeAsync 方法。请使用其他方法调用。");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<object> MethodInvoke(object instance, object[] args)
|
||||
{
|
||||
if (args is null)
|
||||
{
|
||||
args = Array.Empty<object>();
|
||||
}
|
||||
if(_emitMethodInfo.IsStatic)
|
||||
if (_emitMethodInfo.IsStatic)
|
||||
{
|
||||
instance = null;
|
||||
}
|
||||
object result = null;
|
||||
if(funcType == 0)
|
||||
if (methodType == EmitMethodType.Func)
|
||||
{
|
||||
result = func.Invoke(instance, args);
|
||||
result = methodInvoke.Invoke(instance, args);
|
||||
|
||||
}
|
||||
else if (funcType == 2)
|
||||
else if (methodType == EmitMethodType.TaskHasResult)
|
||||
{
|
||||
result = await hasResultTask(instance, args);
|
||||
}
|
||||
else if (funcType == 1)
|
||||
result = await methodHasResultTask(instance, args);
|
||||
}
|
||||
else if (methodType == EmitMethodType.Task)
|
||||
{
|
||||
await task(instance, args);
|
||||
await methodTask(instance, args);
|
||||
result = null;
|
||||
}
|
||||
else
|
||||
@@ -148,5 +288,6 @@ namespace Serein.Library
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace Serein.Library
|
||||
|
||||
/// <summary>
|
||||
/// <para>是否为显式参数(固定值/表达式)</para>
|
||||
/// <para>如果为 true ,则使用UI输入的文本值作为入参数据。</para>
|
||||
/// <para>如果为 true ,则使用输入的文本值作为入参数据。</para>
|
||||
/// <para>如果为 false ,则在当前流程上下文中,根据 ArgDataSourceNodeGuid 查找到对应节点,并根据 ArgDataSourceNodeGuid 判断如何获取其返回的数据,以此作为入参数据。</para>
|
||||
/// </summary>
|
||||
[PropertyInfo(IsNotification = true)]
|
||||
@@ -224,23 +224,14 @@ namespace Serein.Library
|
||||
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. 来自其他节点
|
||||
// 4. 来自其他节点
|
||||
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;
|
||||
var prevNodeGuid = context.GetPreviousNode(NodeModel.Guid);
|
||||
inputParameter = prevNodeGuid != null ? context.GetFlowData(prevNodeGuid)?.Value : null;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -250,7 +241,7 @@ namespace Serein.Library
|
||||
if (!env.TryGetNodeModel(ArgDataSourceNodeGuid, out var sourceNode))
|
||||
throw new Exception($"[arg{Index}] 节点[{ArgDataSourceNodeGuid}]不存在");
|
||||
|
||||
if (sourceNode.IsPublic
|
||||
if (sourceNode.IsPublic // 如果运行上一节点是[FlowCall]节点(则从该节点获取入参)
|
||||
&& env.TryGetNodeModel(prevNodeGuid, out var prevNode)
|
||||
&& prevNode.ControlType == NodeControlType.FlowCall
|
||||
&& env.TryGetNodeModel(context.GetPreviousNode(NodeModel.Guid), out var sourceNodeTemp)
|
||||
@@ -259,13 +250,13 @@ namespace Serein.Library
|
||||
|
||||
if (ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeData)
|
||||
inputParameter = context.GetFlowData(sourceNode.Guid)?.Value;
|
||||
else if (ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeDataOfInvoke)
|
||||
else if (ArgDataSourceType == ConnectionArgSourceType.GetOtherNodeDataOfInvoke) // 立刻执行目标节点获取参数
|
||||
inputParameter = (await sourceNode.ExecutingAsync(context, CancellationToken.None)).Value;
|
||||
else
|
||||
throw new Exception("无效的 ArgDataSourceType");
|
||||
}
|
||||
|
||||
// 6. 表达式处理
|
||||
// 5. 表达式处理
|
||||
if (IsExplicitData && DataValue.StartsWith("@", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var lower = DataValue.ToLowerInvariant();
|
||||
@@ -275,7 +266,7 @@ namespace Serein.Library
|
||||
}
|
||||
}
|
||||
|
||||
// 7. 类型转换
|
||||
// 6. 类型转换
|
||||
if (!DataType.IsValueType && inputParameter is null)
|
||||
throw new Exception($"[arg{Index}] 参数不能为null");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user