feat(helper) : 现在EmitHelper创建方法时可以正确处理具备具备ref、out的方法入参,以及在Task中返回值类型

This commit is contained in:
fengjiayi
2026-01-27 17:33:48 +08:00
parent f93d46565f
commit 791cb8d37f
2 changed files with 142 additions and 96 deletions

View File

@@ -80,7 +80,7 @@ namespace Serein.Library
public DelegateDetails(MethodInfo methodInfo) public DelegateDetails(MethodInfo methodInfo)
{ {
emitType = EmitType.MethodInvoke; emitType = EmitType.MethodInvoke;
var emitMethodType = EmitHelper.CreateDynamicMethod(methodInfo, out var emitDelegate); var emitMethodType = EmitHelper.CreateMethod(methodInfo, out var emitDelegate);
_emitMethodInfo = emitMethodType; _emitMethodInfo = emitMethodType;
_emitDelegate = emitDelegate; _emitDelegate = emitDelegate;
methodType = _emitMethodInfo.EmitMethodType; methodType = _emitMethodInfo.EmitMethodType;

View File

@@ -40,7 +40,9 @@ namespace Serein.Library.Utils
/// </summary> /// </summary>
public bool IsStatic { get; set; } public bool IsStatic { get; set; }
public bool HasByRefParameters { get; set; }
public int[] ByRefParameterIndexes { get; set; } = [];
} }
/// <summary> /// <summary>
@@ -98,132 +100,176 @@ namespace Serein.Library.Utils
/// <param name="methodInfo"></param> /// <param name="methodInfo"></param>
/// <param name="delegate"></param> /// <param name="delegate"></param>
/// <returns></returns> /// <returns></returns>
public static EmitMethodInfo CreateDynamicMethod(MethodInfo methodInfo,out Delegate @delegate) /// <summary>
/// 根据方法信息创建动态调用的委托,返回方法类型,以及传出一个委托
/// </summary>
/// <param name="methodInfo"></param>
/// <param name="delegate"></param>
/// <returns></returns>
public static EmitMethodInfo CreateMethod(MethodInfo methodInfo, out Delegate @delegate)
{ {
if (methodInfo.DeclaringType == null) if (methodInfo.DeclaringType == null)
{
throw new ArgumentNullException(nameof(methodInfo.DeclaringType)); throw new ArgumentNullException(nameof(methodInfo.DeclaringType));
}
EmitMethodInfo emitMethodInfo = new EmitMethodInfo(); bool isStatic = methodInfo.IsStatic;
bool IsTask = IsGenericTask(methodInfo.ReturnType, out var taskGenericsType); bool isTask = IsGenericTask(methodInfo.ReturnType, out var taskResultType);
bool IsTaskGenerics = taskGenericsType != null; bool isTaskGeneric = taskResultType != null;
DynamicMethod dynamicMethod;
Type dynamicReturnType;
Type returnType; if (!isTask)
if (!IsTask) dynamicReturnType = typeof(object);
{
// 普通方法
returnType = typeof(object);
}
else else
dynamicReturnType = isTaskGeneric ? typeof(Task<object>) : typeof(Task);
var dynamicMethod = new DynamicMethod(
methodInfo.Name + "_Emit",
dynamicReturnType,
new[] { typeof(object), typeof(object[]) },
restrictedSkipVisibility: true);
ILGenerator il = dynamicMethod.GetILGenerator();
var parameters = methodInfo.GetParameters();
// ==============================
// 1. 声明 ref / out / in 局部变量
// ==============================
LocalBuilder?[] locals = new LocalBuilder?[parameters.Length];
List<int> byRefIndexes = new();
for (int i = 0; i < parameters.Length; i++)
{ {
// 异步方法 if (parameters[i].ParameterType.IsByRef)
if (IsTaskGenerics)
{ {
returnType = typeof(Task<object>); var elementType = parameters[i].ParameterType.GetElementType()!;
locals[i] = il.DeclareLocal(elementType);
byRefIndexes.Add(i);
}
}
// ==============================
// 2. 初始化 ref / in 参数
// ==============================
for (int i = 0; i < parameters.Length; i++)
{
var p = parameters[i];
if (!p.ParameterType.IsByRef || p.IsOut)
continue;
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldc_I4, i);
il.Emit(OpCodes.Ldelem_Ref);
var elementType = p.ParameterType.GetElementType()!;
if (elementType.IsValueType)
il.Emit(OpCodes.Unbox_Any, elementType);
else
il.Emit(OpCodes.Castclass, elementType);
il.Emit(OpCodes.Stloc, locals[i]!);
}
// ==============================
// 3. 加载实例
// ==============================
if (!isStatic)
{
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Castclass, methodInfo.DeclaringType);
}
// ==============================
// 4. 加载参数
// ==============================
for (int i = 0; i < parameters.Length; i++)
{
var p = parameters[i];
if (p.ParameterType.IsByRef)
{
il.Emit(OpCodes.Ldloca, locals[i]!);
} }
else else
{ {
returnType = typeof(Task); il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldc_I4, i);
il.Emit(OpCodes.Ldelem_Ref);
if (p.ParameterType.IsValueType)
il.Emit(OpCodes.Unbox_Any, p.ParameterType);
else
il.Emit(OpCodes.Castclass, p.ParameterType);
} }
} }
// ==============================
// 5. 调用方法
// ==============================
il.Emit(isStatic ? OpCodes.Call : OpCodes.Callvirt, methodInfo);
// ==============================
dynamicMethod = new DynamicMethod( // 6. 回写 ref / out 参数
name: methodInfo.Name + "_DynamicEmitMethod", // ==============================
returnType: returnType, for (int i = 0; i < parameters.Length; i++)
parameterTypes: new[] { typeof(object), typeof(object[]) }, // 方法实例、方法入参
restrictedSkipVisibility: true // 跳过私有方法访问限制
);
var il = dynamicMethod.GetILGenerator();
// 判断是否为静态方法
bool isStatic = methodInfo.IsStatic;
if (isStatic)
{ {
// 如果是静态方法直接跳过实例不加载Ldarg_0 if (!parameters[i].ParameterType.IsByRef)
} continue;
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; var elementType = parameters[i].ParameterType.GetElementType()!;
if (paramType.IsValueType) // 如果参数是值类型,拆箱
{
il.Emit(OpCodes.Unbox_Any, paramType);
}
//else if (paramType.IsGenericParameter) // 如果是泛型参数,直接转换
//{
// il.Emit(OpCodes.Castclass, paramType);
//}
else // 如果是引用类型,直接转换
{
il.Emit(OpCodes.Castclass, paramType);
}
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldc_I4, i);
il.Emit(OpCodes.Ldloc, locals[i]!);
if (elementType.IsValueType)
il.Emit(OpCodes.Box, elementType);
il.Emit(OpCodes.Stelem_Ref);
} }
// 调用方法:静态方法使用 Call实例方法使用 Callvirt // ==============================
if (isStatic) // 7. 处理返回值
{ // ==============================
il.Emit(OpCodes.Call, methodInfo); // 对于静态方法,使用 Call
}
else
{
il.Emit(OpCodes.Callvirt, methodInfo); // 对于实例方法,使用 Callvirt
}
//// 处理返回值如果没有返回值则返回null
if (methodInfo.ReturnType == typeof(void)) if (methodInfo.ReturnType == typeof(void))
{ {
il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Ldnull);
} }
else if (methodInfo.ReturnType.IsValueType) else if (!isTask && methodInfo.ReturnType.IsValueType)
{ {
il.Emit(OpCodes.Box, methodInfo.ReturnType); // 如果是值类型,将其装箱 il.Emit(OpCodes.Box, methodInfo.ReturnType);
} }
// 处理返回值如果没有返回值则返回null
il.Emit(OpCodes.Ret); // 返回 il.Emit(OpCodes.Ret);
EmitMethodType emitMethodType;
if (IsTask) // ==============================
// 8. 创建委托
// ==============================
EmitMethodType emitType;
if (!isTask)
{ {
if (IsTaskGenerics) emitType = EmitMethodType.Func;
{ @delegate = dynamicMethod.CreateDelegate(
emitMethodType = EmitMethodType.TaskHasResult; typeof(Func<object, object[], object>));
@delegate = dynamicMethod.CreateDelegate(typeof(Func<object, object[], Task<object>>)); }
} else if (isTaskGeneric)
else {
{ emitType = EmitMethodType.TaskHasResult;
emitMethodType = EmitMethodType.Task; @delegate = dynamicMethod.CreateDelegate(
@delegate = dynamicMethod.CreateDelegate(typeof(Func<object, object[], Task>)); typeof(Func<object, object[], Task<object>>));
}
} }
else else
{ {
emitMethodType = EmitMethodType.Func; emitType = EmitMethodType.Task;
@delegate = dynamicMethod.CreateDelegate(typeof(Func<object, object[], object>)); @delegate = dynamicMethod.CreateDelegate(
typeof(Func<object, object[], Task>));
} }
return new EmitMethodInfo return new EmitMethodInfo
{ {
EmitMethodType = emitMethodType, EmitMethodType = emitType,
DeclaringType = methodInfo.DeclaringType, DeclaringType = methodInfo.DeclaringType,
IsAsync = IsTask, IsAsync = isTask,
IsStatic = isStatic IsStatic = isStatic,
HasByRefParameters = byRefIndexes.Count > 0,
ByRefParameterIndexes = byRefIndexes.ToArray()
}; };
} }