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

Mono.Cecil:获取作为泛型参数传入的委托的方法引用

解决Mono.Cecil无法解析委托工厂中具体类型的思路

核心原因

你看到的!!0是编译器生成的闭包类占位符——Lambda表达式作为委托参数传递时,会被编译器自动转换成匿名委托,逻辑会封装到一个自动生成的私有类方法里,而非直接内联在AddSingleton调用的代码位置。所以直接查看AddSingleton调用的IL指令,看不到MongoDBContext的引用,因为委托本身指向的是那个生成类的方法。

具体解决步骤

  • 定位委托的目标方法
    找到AddSingleton调用的第二个参数(即Func委托),它本质是System.Func<IServiceProvider, IMongoDBContext>类型的实例。在IL中,这个参数通过ldftn(加载函数指针)或newobj创建,你需要追踪这个委托指向的实际方法。这类方法通常是编译器生成的,名称类似<Bar>b__0_0,所属类格式为包含Lambda的类+<>c__DisplayClassX_Y(比如Foo+<>c__DisplayClass0_0)。

  • 解析闭包类和目标方法
    通过Mono.Cecil找到生成的方法后,分析该方法的IL指令,就能看到调用MongoDBContext构造函数的指令(比如newobj instance void MongoDBContext::.ctor(string))。可以通过方法的DeclaringType属性找到对应的自动生成闭包类。

  • 泛型参数解析
    !!0对应AddSingleton<TService>中的泛型参数TService(也就是IMongoDBContext),需要通过MethodReference的GenericArguments属性解析这个泛型参数的实际类型,再结合委托的返回类型验证目标方法的返回值是否匹配。

Mono.Cecil操作片段示例

// 假设已定位到AddSingleton的MethodCallInstruction
var addSingletonCall = ...;
// 获取委托参数对应的MethodReference
var delegateArg = addSingletonCall.Operand as MethodReference;
if (delegateArg != null && delegateArg.DeclaringType.FullName.StartsWith("System.Func`2"))
{
    // 回溯找到创建委托的指令(ldftn或newobj)
    var instruction = addSingletonCall.Previous;
    while (instruction != null && instruction.OpCode != OpCodes.Ldftn && instruction.OpCode != OpCodes.Newobj)
    {
        instruction = instruction.Previous;
    }
    if (instruction?.Operand is MethodReference targetMethod)
    {
        // targetMethod就是Lambda对应的实际方法
        Console.WriteLine($"Lambda对应方法: {targetMethod.FullName}");
        // 解析该方法的IL指令
        var methodBody = targetMethod.Resolve().Body;
        foreach (var ilInstr in methodBody.Instructions)
        {
            // 查找MongoDBContext的构造函数调用
            if (ilInstr.OpCode == OpCodes.Newobj && ilInstr.Operand is MethodReference ctor)
            {
                if (ctor.DeclaringType.Name == "MongoDBContext")
                {
                    Console.WriteLine("找到目标构造函数: " + ctor.FullName);
                }
            }
        }
    }
}

注意事项

  • 编译器优化会影响闭包类生成:如果Lambda没有捕获外部变量,部分编译器会将方法生成在包含类的静态方法中,而非闭包类,但核心思路仍是追踪委托的目标方法。
  • 泛型方法解析需注意:AddSingleton是泛型扩展方法,要先解析它的GenericArguments得到TService的实际类型,再对应委托的类型参数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 18:56:01