Files
serein-flow/Library/Utils/EmitHelper.cs

638 lines
23 KiB
C#
Raw Normal View History

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
2024-11-02 16:48:40 +08:00
using System.Reactive;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Library.Utils
{
2024-10-11 19:31:34 +08:00
/// <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
{
2024-10-11 19:31:34 +08:00
/// <summary>
/// 普通的方法。如果方法返回void时将会返回null。
/// </summary>
Func,
2024-10-11 19:31:34 +08:00
/// <summary>
/// 无返回值的异步方法
/// </summary>
Task,
2024-10-11 19:31:34 +08:00
/// <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;
2024-11-02 16:48:40 +08:00
Type returnType;
if (!IsTask)
{
// 普通方法
returnType = typeof(object);
2024-11-02 16:48:40 +08:00
}
else
{
2024-11-02 16:48:40 +08:00
// 异步方法
if (IsTaskGenerics)
{
2024-11-02 16:48:40 +08:00
returnType = typeof(Task<object>);
}
else
{
2024-11-02 16:48:40 +08:00
returnType = typeof(Task);
}
}
2024-11-02 16:48:40 +08:00
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;
}
}
}