mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-03 00:00:49 +08:00
暂时实现了简陋的脚本AST分析解释,后面再绑定到控件上
This commit is contained in:
119
Serein.Script/Tool/DelegateDetails.cs
Normal file
119
Serein.Script/Tool/DelegateDetails.cs
Normal file
@@ -0,0 +1,119 @@
|
||||
using Serein.Library.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static Serein.Library.Utils.EmitHelper;
|
||||
|
||||
namespace Serein.Library
|
||||
{
|
||||
/// <summary>
|
||||
/// Emit创建的委托描述,用于WebApi、WebSocket、NodeFlow动态调用方法的场景。
|
||||
/// 一般情况下你无须关注内部细节,只需要调用 Invoke() 方法即可。
|
||||
/// </summary>
|
||||
public class DelegateDetails
|
||||
{
|
||||
/// <summary>
|
||||
/// 根据方法信息构建Emit委托
|
||||
/// </summary>
|
||||
/// <param name="methodInfo"></param>
|
||||
public DelegateDetails(MethodInfo methodInfo)
|
||||
{
|
||||
var emitMethodType = EmitHelper.CreateDynamicMethod(methodInfo, out var emitDelegate);
|
||||
_emitMethodInfo = emitMethodType;
|
||||
_emitDelegate = emitDelegate;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*/// <summary>
|
||||
/// 更新委托方法
|
||||
/// </summary>
|
||||
/// <param name="EmitMethodType"></param>
|
||||
/// <param name="EmitDelegate"></param>
|
||||
public void Upload(EmitMethodType EmitMethodType, Delegate EmitDelegate)
|
||||
{
|
||||
_emitMethodType = EmitMethodType;
|
||||
_emitDelegate = EmitDelegate;
|
||||
}*/
|
||||
|
||||
private Delegate _emitDelegate;
|
||||
private EmitMethodInfo _emitMethodInfo;
|
||||
|
||||
///// <summary>
|
||||
///// <para>普通方法:Func<object,object[],object></para>
|
||||
///// <para>异步方法:Func<object,object[],Task></para>
|
||||
///// <para>异步有返回值方法:Func<object,object[],Task<object>></para>
|
||||
///// </summary>
|
||||
//public Delegate EmitDelegate { get => _emitDelegate; }
|
||||
///// <summary>
|
||||
///// 表示Emit构造的委托类型
|
||||
///// </summary>
|
||||
//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>
|
||||
public async Task<object> InvokeAsync(object instance, object[] args)
|
||||
{
|
||||
if (args is null)
|
||||
{
|
||||
args = Array.Empty<object>();
|
||||
}
|
||||
if(_emitMethodInfo.IsStatic)
|
||||
{
|
||||
instance = null;
|
||||
}
|
||||
object result = null;
|
||||
if (_emitDelegate is Func<object, object[], Task<object>> hasResultTask)
|
||||
{
|
||||
result = await hasResultTask(instance, args);
|
||||
}
|
||||
else if (_emitDelegate is Func<object, object[], Task> task)
|
||||
{
|
||||
await task.Invoke(instance, args);
|
||||
}
|
||||
else if (_emitDelegate is Func<object, object[], object> func)
|
||||
{
|
||||
result = func.Invoke(instance, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException("创建了非预期委托(应该不会出现)");
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
|
||||
//try
|
||||
//{
|
||||
|
||||
//}
|
||||
//catch
|
||||
//{
|
||||
// throw;
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
203
Serein.Script/Tool/EmitHelper.cs
Normal file
203
Serein.Script/Tool/EmitHelper.cs
Normal file
@@ -0,0 +1,203 @@
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
namespace Serein.Library.Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// Emit创建委托工具类
|
||||
/// </summary>
|
||||
public class EmitHelper
|
||||
{
|
||||
|
||||
public class EmitMethodInfo
|
||||
{
|
||||
public Type DeclaringType { get; set; }
|
||||
/// <summary>
|
||||
/// 是异步方法
|
||||
/// </summary>
|
||||
public bool IsTask { get; set; }
|
||||
/// <summary>
|
||||
/// 是静态的
|
||||
/// </summary>
|
||||
public bool IsStatic { get; set; }
|
||||
}
|
||||
|
||||
public enum EmitMethodType
|
||||
{
|
||||
/// <summary>
|
||||
/// 普通的方法。如果方法返回void时,将会返回null。
|
||||
/// </summary>
|
||||
Func,
|
||||
/// <summary>
|
||||
/// 无返回值的异步方法
|
||||
/// </summary>
|
||||
Task,
|
||||
/// <summary>
|
||||
/// 有返回值的异步方法
|
||||
/// </summary>
|
||||
HasResultTask,
|
||||
|
||||
/// <summary>
|
||||
/// 普通的方法。如果方法返回void时,将会返回null。
|
||||
/// </summary>
|
||||
StaticFunc,
|
||||
/// <summary>
|
||||
/// 无返回值的异步方法
|
||||
/// </summary>
|
||||
StaticTask,
|
||||
}
|
||||
|
||||
public static bool IsGenericTask(Type returnType, out Type taskResult)
|
||||
{
|
||||
// 判断是否为 Task 类型或泛型 Task<T>
|
||||
if (returnType == typeof(Task))
|
||||
{
|
||||
taskResult = null;
|
||||
return true;
|
||||
}
|
||||
else if (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(Task<>))
|
||||
{
|
||||
// 获取泛型参数类型
|
||||
Type genericArgument = returnType.GetGenericArguments()[0];
|
||||
taskResult = genericArgument;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
taskResult = null;
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 根据方法信息创建动态调用的委托,返回方法类型,以及传出一个委托
|
||||
/// </summary>
|
||||
/// <param name="methodInfo"></param>
|
||||
/// <param name="delegate"></param>
|
||||
/// <returns></returns>
|
||||
public static EmitMethodInfo CreateDynamicMethod(MethodInfo methodInfo,out Delegate @delegate)
|
||||
{
|
||||
EmitMethodInfo emitMethodInfo = new EmitMethodInfo();
|
||||
bool IsTask = IsGenericTask(methodInfo.ReturnType, out var taskGenericsType);
|
||||
bool IsTaskGenerics = taskGenericsType != null;
|
||||
DynamicMethod dynamicMethod;
|
||||
|
||||
Type returnType;
|
||||
if (!IsTask)
|
||||
{
|
||||
// 普通方法
|
||||
returnType = typeof(object);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// 异步方法
|
||||
if (IsTaskGenerics)
|
||||
{
|
||||
returnType = typeof(Task<object>);
|
||||
}
|
||||
else
|
||||
{
|
||||
returnType = typeof(Task);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
dynamicMethod = new DynamicMethod(
|
||||
name: methodInfo.Name + "_DynamicEmitMethod",
|
||||
returnType: returnType,
|
||||
parameterTypes: new[] { typeof(object), typeof(object[]) }, // 方法实例、方法入参
|
||||
restrictedSkipVisibility: true // 跳过私有方法访问限制
|
||||
);
|
||||
|
||||
var il = dynamicMethod.GetILGenerator();
|
||||
|
||||
// 判断是否为静态方法
|
||||
bool isStatic = methodInfo.IsStatic;
|
||||
|
||||
if (isStatic)
|
||||
{
|
||||
// 如果是静态方法,直接跳过实例(不加载Ldarg_0)
|
||||
}
|
||||
else
|
||||
{
|
||||
// 加载实例 (this) 对于非静态方法
|
||||
il.Emit(OpCodes.Ldarg_0);
|
||||
il.Emit(OpCodes.Castclass, methodInfo.DeclaringType); // 将 ISocketControlBase 转换为目标类类型
|
||||
}
|
||||
// 加载方法参数
|
||||
var methodParams = methodInfo.GetParameters();
|
||||
for (int i = 0; i < methodParams.Length; i++)
|
||||
{
|
||||
il.Emit(OpCodes.Ldarg_1); // 加载参数数组
|
||||
il.Emit(OpCodes.Ldc_I4, i); // 加载当前参数索引
|
||||
il.Emit(OpCodes.Ldelem_Ref); // 取出数组元素
|
||||
|
||||
var paramType = methodParams[i].ParameterType;
|
||||
if (paramType.IsValueType) // 如果参数是值类型,拆箱
|
||||
{
|
||||
il.Emit(OpCodes.Unbox_Any, paramType);
|
||||
}
|
||||
//else if (paramType.IsGenericParameter) // 如果是泛型参数,直接转换
|
||||
//{
|
||||
// il.Emit(OpCodes.Castclass, paramType);
|
||||
//}
|
||||
else // 如果是引用类型,直接转换
|
||||
{
|
||||
il.Emit(OpCodes.Castclass, paramType);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 调用方法:静态方法使用 Call,实例方法使用 Callvirt
|
||||
if (isStatic)
|
||||
{
|
||||
il.Emit(OpCodes.Call, methodInfo); // 对于静态方法,使用 Call
|
||||
}
|
||||
else
|
||||
{
|
||||
il.Emit(OpCodes.Callvirt, methodInfo); // 对于实例方法,使用 Callvirt
|
||||
}
|
||||
|
||||
//// 处理返回值,如果没有返回值,则返回null
|
||||
if (methodInfo.ReturnType == typeof(void))
|
||||
{
|
||||
il.Emit(OpCodes.Ldnull);
|
||||
}
|
||||
else if (methodInfo.ReturnType.IsValueType)
|
||||
{
|
||||
il.Emit(OpCodes.Box, methodInfo.ReturnType); // 如果是值类型,将其装箱
|
||||
}
|
||||
// 处理返回值,如果没有返回值,则返回null
|
||||
il.Emit(OpCodes.Ret); // 返回
|
||||
if (IsTask)
|
||||
{
|
||||
if (IsTaskGenerics)
|
||||
{
|
||||
@delegate = dynamicMethod.CreateDelegate(typeof(Func<object, object[], Task<object>>));
|
||||
}
|
||||
else
|
||||
{
|
||||
@delegate = dynamicMethod.CreateDelegate(typeof(Func<object, object[], Task>));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@delegate = dynamicMethod.CreateDelegate(typeof(Func<object, object[], object>));
|
||||
|
||||
}
|
||||
return new EmitMethodInfo
|
||||
{
|
||||
DeclaringType = methodInfo.DeclaringType,
|
||||
IsTask = IsTask,
|
||||
IsStatic = isStatic
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user