You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# Reflection Emit调用泛型接口实现类动态方法时触发无效程序异常

问题分析与解决方案

核心问题:栈不平衡引发无效程序异常

你遇到的问题根源在于返回值处理不匹配:

  • 当接口方法为void时,你的IL代码调用Invoke后直接执行Ret,但如果Invoke方法返回object(常见拦截方法签名),栈上会遗留未处理的返回值,CLR会判定栈状态非法,抛出异常。
  • 有返回值的方法刚好能匹配Invoke的返回值(后续隐式转换),因此可以正常运行。

另外,MethodBase.GetCurrentMethod()获取的是动态生成的代理方法,而非原始接口方法,这会导致拦截逻辑拿到错误的方法元数据,后续处理泛型参数时也可能出现问题。

具体修改步骤

1. 区分处理void和非void方法的返回值

调用Invoke后,根据原方法的返回类型决定后续操作:

  • 若原方法返回void,使用OpCodes.Pop指令移除栈上的返回值
  • 若原方法有返回值,将Invoke返回的object拆箱/转换为原返回类型

2. 直接使用原始接口方法的MethodInfo

不在IL中通过GetCurrentMethod()获取方法,而是直接将原始interfaceMethod的MethodInfo作为常量传入IL,避免拿到错误的方法实例。

3. 修正泛型参数的类型处理

确保泛型参数的约束和类型替换完全正确,特别是值类型装箱时使用正确的泛型参数类型。

修改后的代码示例

var invokeMethod = typeof(ServiceInterceptor).GetMethod(nameof(Invoke), BindingFlags.Instance | BindingFlags.NonPublic) ?? throw new InvalidOperationException("Could not get Invoke method");
var interfaceMethods = GetAllInterfaceMethods(interfaceType);
var getTypeFromHandle = typeof(Type).GetMethod(nameof(Type.GetTypeFromHandle), BindingFlags.Static | BindingFlags.Public) ?? throw new InvalidOperationException("Could not get GetTypeFromHandle method");

foreach (var interfaceMethod in interfaceMethods)
{
    var interfaceMethodTypeBuilder = serviceInterceptorTypeBuilder.DefineMethod(
        interfaceMethod.Name, 
        interfaceMethod.Attributes & ~MethodAttributes.Abstract, 
        interfaceMethod.CallingConvention);
    builtMethods.Add(interfaceMethodTypeBuilder);

    // 处理泛型参数
    var interfaceMethodGenericArguments = interfaceMethod.GetGenericArguments();
    var interfaceMethodGenericParametersMap = new Dictionary<Type, GeneraticParameterTypeWithInitialization>();
    if (serviceInterceptorGenericParametersMap != null && serviceInterceptorGenericParametersMap.Any())
    {
        foreach (var parameterMap in serviceInterceptorGenericParametersMap)
        {
            interfaceMethodGenericParametersMap[parameterMap.Key] = parameterMap.Value;
        }
    }
    if (interfaceMethodGenericArguments.Any())
    {
        var genericMethodParameters = interfaceMethodTypeBuilder.DefineGenericParameters(
            interfaceMethodGenericArguments.Select(arg => arg.Name).ToArray());
        for (int i = 0; i < genericMethodParameters.Length; i++)
        {
            interfaceMethodGenericParametersMap[interfaceMethodGenericArguments[i]] = 
                new GeneraticParameterTypeWithInitialization { GenericTypeParameterBuilder = genericMethodParameters[i] };
        }
        foreach (var interfaceMethodGenericArgument in interfaceMethodGenericArguments)
        {
            foreach (var constraint in interfaceMethodGenericArgument.GetGenericParameterConstraints())
            {
                var replacedConstraint = ReplaceGenericArgumentsAndConstraintsFromType(constraint, interfaceMethodGenericParametersMap);
                if (replacedConstraint.IsInterface)
                {
                    interfaceMethodGenericParametersMap[interfaceMethodGenericArgument].GenericTypeParameterBuilder.SetInterfaceConstraints(replacedConstraint);
                    continue;
                }
                interfaceMethodGenericParametersMap[interfaceMethodGenericArgument].GenericTypeParameterBuilder.SetBaseTypeConstraint(replacedConstraint);
                interfaceMethodGenericParametersMap[interfaceMethodGenericArgument].GenericTypeParameterBuilder.SetGenericParameterAttributes(
                    constraint.GenericParameterAttributes & ~GenericParameterAttributes.Covariant & ~GenericParameterAttributes.Contravariant);
            }
        }
    }

    // 设置方法参数和返回类型
    var interfaceParameters = interfaceMethod.GetParameters();
    var interfaceMethodParameters = interfaceParameters.Select(x => ReplaceGenericArgumentsFromType(x.ParameterType, serviceInterceptorGenericParametersMap)).ToArray();
    interfaceMethodTypeBuilder.SetParameters(interfaceMethodParameters);
    var returnType = ReplaceGenericArgumentsFromType(interfaceMethod.ReturnType, serviceInterceptorGenericParametersMap);
    interfaceMethodTypeBuilder.SetReturnType(returnType);

    var ilGenerator = interfaceMethodTypeBuilder.GetILGenerator();
    var localOjectParamList = ilGenerator.DeclareLocal(typeof(object[]));
    var localMethodInfo = ilGenerator.DeclareLocal(typeof(MethodInfo));

    // 直接加载原始接口方法的MethodInfo(替代GetCurrentMethod)
    ilGenerator.Emit(OpCodes.Ldtoken, interfaceMethod);
    ilGenerator.Emit(OpCodes.Call, typeof(MethodBase).GetMethod(nameof(MethodBase.GetMethodFromHandle), BindingFlags.Static | BindingFlags.Public)!);
    ilGenerator.Emit(OpCodes.Castclass, typeof(MethodInfo));
    ilGenerator.Emit(OpCodes.Stloc, localMethodInfo);

    // 处理参数数组
    if (interfaceParameters.Any())
    {
        ilGenerator.Emit(OpCodes.Ldc_I4, interfaceParameters.Length);
        ilGenerator.Emit(OpCodes.Newarr, typeof(object));
        ilGenerator.Emit(OpCodes.Stloc, localOjectParamList);

        for (short parameterIndex = 0; parameterIndex < interfaceParameters.Length; parameterIndex++)
        {
            var paramType = interfaceMethodParameters[parameterIndex];
            ilGenerator.Emit(OpCodes.Ldloc, localOjectParamList);
            ilGenerator.Emit(OpCodes.Ldc_I4, parameterIndex);
            ilGenerator.Emit(OpCodes.Ldarg, (short)(parameterIndex + 1));

            // 值类型装箱,引用类型直接存储
            if (paramType.IsValueType && paramType != typeof(void))
            {
                ilGenerator.Emit(OpCodes.Box, paramType);
            }
            ilGenerator.Emit(OpCodes.Stelem_Ref);
        }

        ilGenerator.Emit(OpCodes.Ldarg_0);
        ilGenerator.Emit(OpCodes.Ldloc, localMethodInfo);
        ilGenerator.Emit(OpCodes.Ldloc, localOjectParamList);
    }
    else
    {
        ilGenerator.Emit(OpCodes.Ldarg_0);
        ilGenerator.Emit(OpCodes.Ldloc, localMethodInfo);
        ilGenerator.Emit(OpCodes.Ldnull);
    }

    // 调用拦截方法
    ilGenerator.Emit(OpCodes.Callvirt, invokeMethod);

    // 处理返回值
    if (returnType == typeof(void))
    {
        // void方法弹出Invoke的返回值,保证栈平衡
        ilGenerator.Emit(OpCodes.Pop);
    }
    else
    {
        // 非void方法将object转换为原返回类型
        if (returnType.IsValueType)
        {
            ilGenerator.Emit(OpCodes.Unbox_Any, returnType);
        }
        else
        {
            ilGenerator.Emit(OpCodes.Castclass, returnType);
        }
    }

    ilGenerator.Emit(OpCodes.Ret);
}

关键修改点说明

  1. 替换GetCurrentMethod逻辑:通过Ldtoken和GetMethodFromHandle获取原始接口方法的MethodInfo,确保拦截逻辑拿到正确的方法元数据。
  2. 返回值分支处理:
    • 针对void方法,调用Pop移除Invoke的返回值,保证栈状态合法
    • 针对非void方法,根据返回类型执行拆箱或类型转换,匹配原方法的返回值要求
  3. 简化参数装箱逻辑:直接判断参数类型是否为值类型,减少多余的局部变量和分支跳转,降低IL代码复杂度。

内容的提问来源于stack exchange,提问作者Alecu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 03:39:53