Files
serein-flow/Library/Utils/EmitHelper.cs
fengjiayi 1bccccc835 1. 重新设计了 JSON门户类的实现
2. Script脚本添加了原始字符串的实现
3. 修复了Script中无法对  \" 双引号转义的问题
4. 新增了对于集合嵌套取值的支持(目前仅是集合取值)
5. 重新设计了FlowWorkManagement任务启动的逻辑,修复了触发器无法正常运行的问题
6. 在ScriptBaseFunc中新增了 json() 本地函数,支持将字符串转为IJsonToken进行取值。
7. EmitHelper对于集合取值时,反射获取“get_item”委托时存在看你多个MethodInfo,现在可以传入子项类型,帮助匹配目标重载方法
2025-07-31 23:59:31 +08:00

638 lines
23 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reactive;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Library.Utils
{
/// <summary>
/// Emit创建委托工具类
/// </summary>
public class EmitHelper
{
/// <summary>
/// 动态方法信息
/// </summary>
public class EmitMethodInfo
{
/// <summary>
/// 方法声明类型
/// </summary>
public Type DeclaringType { get; set; }
/// <summary>
/// 方法类型
/// </summary>
public EmitMethodType EmitMethodType { get; set; }
/// <summary>
/// 是异步方法
/// </summary>
public bool IsAsync { get; set; }
/// <summary>
/// 是静态的
/// </summary>
public bool IsStatic { get; set; }
}
/// <summary>
/// 方法类型枚举
/// </summary>
public enum EmitMethodType
{
/// <summary>
/// 普通的方法。如果方法返回void时将会返回null。
/// </summary>
Func,
/// <summary>
/// 无返回值的异步方法
/// </summary>
Task,
/// <summary>
/// 有返回值的异步方法
/// </summary>
TaskHasResult,
}
/// <summary>
/// 判断一个类型是否为泛型 Task&lt;T&gt; 或 Task并返回泛型参数类型如果有的话
/// </summary>
/// <param name="returnType"></param>
/// <param name="taskResult"></param>
/// <returns></returns>
#nullable enable
public static bool IsGenericTask(Type returnType, out Type? taskResult)
{
// 判断是否为 Task 类型或泛型 Task<T>
if (returnType == typeof(Task))
{
taskResult = typeof(void);
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)
{
if (methodInfo.DeclaringType == null)
{
throw new ArgumentNullException(nameof(methodInfo.DeclaringType));
}
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); // 返回
EmitMethodType emitMethodType;
if (IsTask)
{
if (IsTaskGenerics)
{
emitMethodType = EmitMethodType.TaskHasResult;
@delegate = dynamicMethod.CreateDelegate(typeof(Func<object, object[], Task<object>>));
}
else
{
emitMethodType = EmitMethodType.Task;
@delegate = dynamicMethod.CreateDelegate(typeof(Func<object, object[], Task>));
}
}
else
{
emitMethodType = EmitMethodType.Func;
@delegate = dynamicMethod.CreateDelegate(typeof(Func<object, object[], object>));
}
return new EmitMethodInfo
{
EmitMethodType = emitMethodType,
DeclaringType = methodInfo.DeclaringType,
IsAsync = IsTask,
IsStatic = isStatic
};
}
/// <summary>
/// 构建字段 Getter 委托Func&lt;object, object&gt;
/// </summary>
public static Func<object, object> CreateFieldGetter(FieldInfo fieldInfo)
{
if (fieldInfo == null)
throw new ArgumentNullException(nameof(fieldInfo));
if (fieldInfo.DeclaringType == null)
throw new ArgumentNullException(nameof(fieldInfo.DeclaringType));
var method = new DynamicMethod(
fieldInfo.Name + "_Get",
typeof(object),
new[] { typeof(object) },
fieldInfo.DeclaringType,
true);
ILGenerator il = method.GetILGenerator();
if (!fieldInfo.IsStatic)
{
// 加载实例
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Castclass, fieldInfo.DeclaringType);
il.Emit(OpCodes.Ldfld, fieldInfo);
}
else
{
il.Emit(OpCodes.Ldsfld, fieldInfo);
}
// 如果是值类型,装箱
if (fieldInfo.FieldType.IsValueType)
il.Emit(OpCodes.Box, fieldInfo.FieldType);
il.Emit(OpCodes.Ret);
return (Func<object, object>)method.CreateDelegate(typeof(Func<object, object>));
}
/// <summary>
/// 构建字段 Setter 委托Action&lt;object, object&gt;
/// </summary>
public static Action<object, object> CreateFieldSetter(FieldInfo fieldInfo)
{
if (fieldInfo == null)
throw new ArgumentNullException(nameof(fieldInfo));
if (fieldInfo.DeclaringType == null)
throw new ArgumentNullException(nameof(fieldInfo.DeclaringType));
if (fieldInfo.IsInitOnly)
throw new InvalidOperationException($"字段 {fieldInfo.Name} 是只读字段,无法设置值。");
var method = new DynamicMethod(
fieldInfo.Name + "_Set",
null,
new[] { typeof(object), typeof(object) },
fieldInfo.DeclaringType,
true);
ILGenerator il = method.GetILGenerator();
if (!fieldInfo.IsStatic)
{
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Castclass, fieldInfo.DeclaringType);
}
// 加载值
il.Emit(OpCodes.Ldarg_1);
if (fieldInfo.FieldType.IsValueType)
il.Emit(OpCodes.Unbox_Any, fieldInfo.FieldType);
else
il.Emit(OpCodes.Castclass, fieldInfo.FieldType);
if (fieldInfo.IsStatic)
il.Emit(OpCodes.Stsfld, fieldInfo);
else
il.Emit(OpCodes.Stfld, fieldInfo);
il.Emit(OpCodes.Ret);
return (Action<object, object>)method.CreateDelegate(typeof(Action<object, object>));
}
/// <summary>
/// 构建属性 Getter 委托Func&lt;object, object&gt;
/// </summary>
public static Func<object, object> CreatePropertyGetter(PropertyInfo propertyInfo)
{
if (propertyInfo == null)
throw new ArgumentNullException(nameof(propertyInfo));
if (propertyInfo.DeclaringType == null)
throw new ArgumentNullException(nameof(propertyInfo.DeclaringType));
var getMethod = propertyInfo.GetGetMethod(true);
if (getMethod == null)
throw new InvalidOperationException($"属性 {propertyInfo.Name} 没有可用的 Getter。");
var method = new DynamicMethod(
propertyInfo.Name + "_Get",
typeof(object),
new[] { typeof(object) },
propertyInfo.DeclaringType,
true);
ILGenerator il = method.GetILGenerator();
if (!getMethod.IsStatic)
{
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Castclass, propertyInfo.DeclaringType);
il.EmitCall(OpCodes.Callvirt, getMethod, null);
}
else
{
il.EmitCall(OpCodes.Call, getMethod, null);
}
// 装箱
if (propertyInfo.PropertyType.IsValueType)
il.Emit(OpCodes.Box, propertyInfo.PropertyType);
il.Emit(OpCodes.Ret);
return (Func<object, object>)method.CreateDelegate(typeof(Func<object, object>));
}
/// <summary>
/// 构建属性 Setter 委托Action&lt;object, object&gt;
/// </summary>
public static Action<object, object> CreatePropertySetter(PropertyInfo propertyInfo)
{
if (propertyInfo == null)
throw new ArgumentNullException(nameof(propertyInfo));
if (propertyInfo.DeclaringType == null)
throw new ArgumentNullException(nameof(propertyInfo.DeclaringType));
var setMethod = propertyInfo.GetSetMethod(true);
if (setMethod == null)
throw new InvalidOperationException($"属性 {propertyInfo.Name} 没有可用的 Setter。");
var method = new DynamicMethod(
propertyInfo.Name + "_Set",
null,
new[] { typeof(object), typeof(object) },
propertyInfo.DeclaringType,
true);
ILGenerator il = method.GetILGenerator();
if (!setMethod.IsStatic)
{
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Castclass, propertyInfo.DeclaringType);
}
// 加载值
il.Emit(OpCodes.Ldarg_1);
if (propertyInfo.PropertyType.IsValueType)
il.Emit(OpCodes.Unbox_Any, propertyInfo.PropertyType);
else
il.Emit(OpCodes.Castclass, propertyInfo.PropertyType);
if (setMethod.IsStatic)
il.EmitCall(OpCodes.Call, setMethod, null);
else
il.EmitCall(OpCodes.Callvirt, setMethod, null);
il.Emit(OpCodes.Ret);
return (Action<object, object>)method.CreateDelegate(typeof(Action<object, object>));
}
/// <summary>
/// 构建数组创建委托Func&lt;int, object[]&gt;
/// </summary>
/// <param name="elementType"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public static Func<int, object> CreateArrayFactory(Type elementType)
{
if (elementType == null) throw new ArgumentNullException(nameof(elementType));
var arrayType = elementType.MakeArrayType();
var dm = new DynamicMethod(
$"NewArray_{elementType.Name}",
typeof(object), // 返回 object
new[] { typeof(int) }, // 参数length
typeof(EmitHelper).Module,
true);
var il = dm.GetILGenerator();
il.Emit(OpCodes.Ldarg_0); // length
il.Emit(OpCodes.Newarr, elementType); // new T[length]
il.Emit(OpCodes.Ret); // 返回 T[]
return (Func<int, object>)dm.CreateDelegate(typeof(Func<int, object>));
}
/// <summary>
/// 构建集合赋值委托Action&lt;object, object, object&gt;
/// </summary>
/// <param name="collectionType"></param>
/// <returns></returns>
/// <exception cref="NotSupportedException"></exception>
public static Action<object, object, object> CreateCollectionSetter(Type collectionType)
{
DynamicMethod dm = new DynamicMethod(
"SetCollectionValue",
null,
new[] { typeof(object), typeof(object), typeof(object) },
typeof(EmitHelper).Module,
true);
ILGenerator il = dm.GetILGenerator();
if (collectionType.IsArray)
{
// (object array, object index, object value) => ((T[])array)[(int)index] = (T)value;
var elementType = collectionType.GetElementType()!;
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Castclass, collectionType); // 转为真实数组类型
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Unbox_Any, typeof(int)); // index
il.Emit(OpCodes.Ldarg_2);
if (elementType.IsValueType)
il.Emit(OpCodes.Unbox_Any, elementType);
else
il.Emit(OpCodes.Castclass, elementType);
il.Emit(OpCodes.Stelem, elementType); // 设置数组元素
il.Emit(OpCodes.Ret);
}
else
{
// 尝试获取 set_Item 方法
MethodInfo? setItem = collectionType.GetMethod("set_Item", BindingFlags.Instance | BindingFlags.Public);
if (setItem == null)
throw new NotSupportedException($"类型 {collectionType} 不支持 set_Item。");
var parameters = setItem.GetParameters();
var indexType = parameters[0].ParameterType;
var valueType = parameters[1].ParameterType;
// (object collection, object index, object value) => ((CollectionType)collection)[(IndexType)index] = (ValueType)value;
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Castclass, collectionType);
il.Emit(OpCodes.Ldarg_1);
if (indexType.IsValueType)
il.Emit(OpCodes.Unbox_Any, indexType);
else
il.Emit(OpCodes.Castclass, indexType);
il.Emit(OpCodes.Ldarg_2);
if (valueType.IsValueType)
il.Emit(OpCodes.Unbox_Any, valueType);
else
il.Emit(OpCodes.Castclass, valueType);
il.Emit(OpCodes.Callvirt, setItem);
il.Emit(OpCodes.Ret);
}
return (Action<object, object, object>)dm.CreateDelegate(typeof(Action<object, object, object>));
}
/// <summary>
/// 构建集合取值委托:(object collection, object index) => object value
/// 支持数组、泛型集合、IDictionary 等类型
/// </summary>
public static Func<object, object, object> CreateCollectionGetter(Type collectionType, Type? itemType = null)
{
DynamicMethod dm = new DynamicMethod(
"GetCollectionValue",
typeof(object),
new[] { typeof(object), typeof(object) },
typeof(EmitHelper).Module,
skipVisibility: true);
ILGenerator il = dm.GetILGenerator();
// 数组类型处理
if (collectionType.IsArray)
{
var elementType = collectionType.GetElementType()!;
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Castclass, collectionType); // 转为真实数组类型
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Unbox_Any, typeof(int)); // 转为int索引
il.Emit(OpCodes.Ldelem, elementType); // 取值
if (elementType.IsValueType)
il.Emit(OpCodes.Box, elementType); // 装箱
il.Emit(OpCodes.Ret);
}
// 非泛型 IDictionary 类型(如 Hashtable、JObject
else if (IsGenericDictionaryType(collectionType, out var keyType, out var valueType))
{
var getItem = collectionType.GetMethod("get_Item", new[] { keyType });
if (getItem == null)
throw new NotSupportedException($"{collectionType} 未实现 get_Item({keyType})");
var returnType = getItem.ReturnType;
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Castclass, collectionType);
il.Emit(OpCodes.Ldarg_1);
if (keyType.IsValueType)
il.Emit(OpCodes.Unbox_Any, keyType);
else
il.Emit(OpCodes.Castclass, keyType);
il.Emit(OpCodes.Callvirt, getItem);
if (returnType.IsValueType)
il.Emit(OpCodes.Box, returnType);
il.Emit(OpCodes.Ret);
}
// 实现 get_Item 方法的类型(如 List<T>, Dictionary<TKey, TValue> 等)
else
{
/*var methodInfos = collectionType.GetMethods(BindingFlags.Instance | BindingFlags.Public);
MethodInfo? getItem;
if (methodInfos.Length > 1)
{
getItem = methodInfos.Where(m => m.Name.Equals("get_Item")).Where(m =>
{
var ps = m.GetParameters().ToArray();
if (ps.Length > 1) return false;
if (ps[0].ParameterType == typeof(object)) return false;
return true;
}).FirstOrDefault();
}
else
{
//getItem = collectionType.GetMethod("get_Item", BindingFlags.Instance | BindingFlags.Public);
getItem = methodInfos.First(m => m.Name.Equals("get_Item"));
}
*/
// GetMethod(name, bindingAttr, binder: null, types, modifiers: null);
MethodInfo? getItem = collectionType.GetMethod("get_Item", bindingAttr: BindingFlags.Instance | BindingFlags.Public, binder: null, types: [itemType], modifiers: null);
if (getItem == null)
throw new NotSupportedException($"类型 {collectionType} 不支持 get_Item。");
var indexParamType = getItem.GetParameters()[0].ParameterType;
var returnType = getItem.ReturnType;
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Castclass, collectionType);
il.Emit(OpCodes.Ldarg_1);
if (indexParamType.IsValueType)
il.Emit(OpCodes.Unbox_Any, indexParamType);
else
il.Emit(OpCodes.Castclass, indexParamType);
il.Emit(OpCodes.Callvirt, getItem);
if (returnType.IsValueType)
il.Emit(OpCodes.Box, returnType);
il.Emit(OpCodes.Ret);
}
return (Func<object, object, object>)dm.CreateDelegate(typeof(Func<object, object, object>));
}
private static bool IsGenericDictionaryType(Type type, out Type keyType, out Type valueType)
{
keyType = null!;
valueType = null!;
var dictInterface = type
.GetInterfaces()
.FirstOrDefault(t =>
t.IsGenericType &&
t.GetGenericTypeDefinition() == typeof(IDictionary<,>));
if (dictInterface != null)
{
var args = dictInterface.GetGenericArguments();
keyType = args[0];
valueType = args[1];
return true;
}
return false;
}
}
}