通过委托通过Emit调用静态泛型方法

本文关键字:静态 泛型方法 调用 Emit | 更新日期: 2023-09-27 18:00:45

我试图创建一个deleagte来调用一个静态泛型方法。但我得到了错误:检测到无效代码!有人知道我的IL怎么了吗?

示例代码中的FindStaticMethod调用正在工作并返回具有给定Type参数的方法信息!

 public delegate object GenericStaticInvoker(params object[] arguments);
 public static GenericStaticInvoker GenericMethodInvokerStaticMethod(Type type, string methodName, Type[] typeArguments, Type[] parameterTypes)
    {
        MethodInfo methodInfo;
        ParameterInfo[] parameters;
        // find the method to be invoked
        FindStaticMethod(type, methodName, typeArguments, parameterTypes, out methodInfo, out parameters);
        string name = string.Format("__MethodInvoker_{0}_ON_{1}", methodInfo.Name, methodInfo.DeclaringType.Name);
        DynamicMethod dynamicMethod;
        dynamicMethod = new DynamicMethod(name, typeof(object), new Type[] { typeof(object[]) }, methodInfo.DeclaringType);
        ILGenerator generator = dynamicMethod.GetILGenerator();
        // define local vars
        if (methodInfo.ReturnType != typeof(void))
            generator.DeclareLocal(methodInfo.ReturnType);
        for (int i = 0; i < parameters.Length; i++)
        {
            // load paramters they are passed as an object array
            generator.Emit(OpCodes.Ldarg_1);
            // load array element
            generator.Emit(OpCodes.Ldc_I4, i);
            generator.Emit(OpCodes.Ldelem_Ref);
            // cast or unbox parameter as needed
            Type parameterType = parameters[i].ParameterType;
            if (parameterType.IsClass)
            {
                generator.Emit(OpCodes.Castclass, parameterType);
            }
            else
            {
                generator.Emit(OpCodes.Unbox_Any, parameterType);
            }
        }
        // call method
        generator.EmitCall(OpCodes.Call, methodInfo, null);
        // handle method return if needed
        if (methodInfo.ReturnType == typeof(void))
        {
            // return null
            generator.Emit(OpCodes.Ldnull);                
            generator.Emit(OpCodes.Ret);
        }
        else
        {
            // box value if needed
            if (methodInfo.ReturnType.IsValueType)
            {
                generator.Emit(OpCodes.Box, methodInfo.ReturnType);
            }
            // store to the local var
            generator.Emit(OpCodes.Stloc_0);
            // load local and return
            generator.Emit(OpCodes.Ldloc_0);
            generator.Emit(OpCodes.Ret);
        }

        // return delegate
        return (GenericStaticInvoker)dynamicMethod.CreateDelegate(typeof(GenericStaticInvoker));
    }

通过委托通过Emit调用静态泛型方法

  • 在实例方法中,"this"参数可以由Ldarg_0加载到评估堆栈上,然后"实际"参数可以用Ldarg_{x}加载(从x1到N)。

  • 当你有一个静态方法时(也有任何lambda的情况,无论它是否反射发射),"实际"参数可以用Ldarg_{x}加载(x 0到N-1)。

  • 概括一下一般情况:"this"引用本身就是一个参数。它的缺失不会在堆栈上留下一个空槽(ldarg.0将并且必须用于第一个非"this"参数)。

因此,在您的特定情况下,您不能使用OpCodes。Ldarg_1确实加载您的params对象[]参数唯一参数:

// ...etc...
for (int i = 0; i < parameters.Length; i++)
{
    // load paramters they are passed as an object array
    generator.Emit(OpCodes.Ldarg_1);
    // ...etc...

您应该使用OpCodes.Ldarg_0:

// ...etc...
for (int i = 0; i < parameters.Length; i++)
{
    // load paramters they are passed as an object array
    generator.Emit(OpCodes.Ldarg_0);
    // ...etc...