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

Mono Cecil中引用泛型实例类型上的泛型实例方法的问题

解决Mono Cecil中引用泛型实例类型上的泛型实例方法问题

我来帮你搞定这个坑!你现在的问题有两个关键点:一是扩展方法里的循环写错了,二是没处理好泛型类型实例和泛型方法实例的先后顺序。咱们一步步理清楚:

首先,你的现有代码的明显bug

看你写的循环逻辑:

foreach (var _argument in genericArguments) {
    _method.GenericArguments.Add(genericArguments); // 这里犯了低级错误!
}

你把整个genericArguments数组添加到方法泛型参数里了,而不是当前遍历的单个_argument。这会导致方法的泛型参数被重复塞入整个数组,肯定会抛出异常。

更关键的:泛型类型与泛型方法的依赖关系

要调用Foo<T1>的Bar<T2>,你必须遵循一个先后顺序:

  1. 先把泛型类型Foo<T1>实例化(比如变成Foo<int>这种具体的泛型类型)
  2. 再从这个实例化后的类型中,获取泛型方法Bar<T2>的定义
  3. 最后把泛型方法Bar<T2>也实例化(比如变成Bar<string>)

跳过第一步直接处理方法,会导致Mono Cecil无法识别方法所属的泛型上下文,必然报错。

修正后的扩展方法+完整使用示例

先把扩展方法改对,再给你一套完整的调用流程:

修正后的MakeGenericMethod扩展方法

using Mono.Cecil;

public static class CecilExtensions
{
    public static GenericInstanceMethod MakeGenericMethod(this MethodReference method, params TypeReference[] genericArguments)
    {
        // 先做合法性检查,避免无效调用
        if (!method.IsGenericMethodDefinition)
            throw new ArgumentException("传入的方法必须是泛型方法定义", nameof(method));
        
        if (genericArguments.Length != method.GenericParameters.Count)
            throw new ArgumentException($"需要{method.GenericParameters.Count}个泛型参数,但只传入了{genericArguments.Length}个", nameof(genericArguments));

        var genericMethod = new GenericInstanceMethod(method);
        foreach (var argument in genericArguments)
        {
            // 这里添加单个泛型参数,而不是整个数组!
            genericMethod.GenericArguments.Add(argument);
        }
        return genericMethod;
    }
}

完整的使用流程示例

假设你已经拿到了目标模块的ModuleDefinition引用,要获取Foo<int>.Bar<string>(int)的方法引用:

// 1. 获取Foo<T1>的泛型类型定义
var fooGenericDef = moduleDefinition.Types.First(t => t.Name == "Foo" && t.IsGenericTypeDefinition);

// 2. 实例化Foo<T1>为具体的泛型类型(比如T1=int)
var fooInstance = new GenericInstanceType(fooGenericDef);
fooInstance.GenericArguments.Add(moduleDefinition.TypeSystem.Int32);

// 3. 从实例化后的Foo类型中,获取Bar<T2>的泛型方法定义
var barGenericDef = fooInstance.Methods.First(m => m.Name == "Bar" && m.IsGenericMethodDefinition);

// 4. 实例化Bar<T2>为具体的泛型方法(比如T2=string)
var barInstance = barGenericDef.MakeGenericMethod(moduleDefinition.TypeSystem.String);

// 现在barInstance就是你需要的Foo<int>.Bar<string>(int)的合法方法引用了

为什么要这么做?

Mono Cecil对泛型的引用有严格的上下文要求:泛型方法必须依附于已经实例化的泛型类型,否则它无法解析类型层面的泛型参数,会抛出类型不匹配的异常。如果直接从原始的Foo<T1>泛型定义拿方法,后续调用时会因为类型上下文缺失而报错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 03:49:44