Mono Cecil中引用泛型实例类型上的泛型实例方法的问题
解决Mono Cecil中引用泛型实例类型上的泛型实例方法问题
我来帮你搞定这个坑!你现在的问题有两个关键点:一是扩展方法里的循环写错了,二是没处理好泛型类型实例和泛型方法实例的先后顺序。咱们一步步理清楚:
首先,你的现有代码的明显bug
看你写的循环逻辑:
foreach (var _argument in genericArguments) { _method.GenericArguments.Add(genericArguments); // 这里犯了低级错误! }
你把整个genericArguments数组添加到方法泛型参数里了,而不是当前遍历的单个_argument。这会导致方法的泛型参数被重复塞入整个数组,肯定会抛出异常。
更关键的:泛型类型与泛型方法的依赖关系
要调用Foo<T1>的Bar<T2>,你必须遵循一个先后顺序:
- 先把泛型类型
Foo<T1>实例化(比如变成Foo<int>这种具体的泛型类型) - 再从这个实例化后的类型中,获取泛型方法
Bar<T2>的定义 - 最后把泛型方法
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
相关产品推荐
相关产品推荐

