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

如何将Func委托转换为IL代码并在动态生成程序集中执行?

解决方案

要解决运行时将Func<object[], object>委托转换为IL并在生成程序集中执行的问题,核心思路是将原委托方法的IL指令复制到生成的动态类型方法中,而非直接引用原方法(避免跨程序集依赖问题)。以下是具体实现步骤和代码:

1. 依赖准备

首先安装Mono.Reflection NuGet包,用于读取原方法的IL指令。

2. 实现核心方法

using Mono.Reflection;
using System.Reflection;
using System.Reflection.Emit;
using System;

public void AddExecutingFunctionToIL(ILGenerator parentIlGenerator, TypeBuilder typeBuilder, Func<object[], object> function)
{
    MethodInfo originalMethod = function.Method;

    // 在动态类型中创建匹配原方法签名的静态方法
    MethodBuilder wrappedMethod = typeBuilder.DefineMethod(
        $"Wrapped_{originalMethod.Name}_{Guid.NewGuid():N}",
        MethodAttributes.Public | MethodAttributes.Static,
        originalMethod.ReturnType,
        originalMethod.GetParameters().Select(p => p.ParameterType).ToArray());

    ILGenerator methodIl = wrappedMethod.GetILGenerator();
    var originalInstructions = originalMethod.GetInstructions();

    // 逐行复制原方法的IL指令,处理不同类型的操作数
    foreach (var instr in originalInstructions)
    {
        switch (instr.OpCode.OperandType)
        {
            case OperandType.InlineMethod:
                methodIl.Emit(instr.OpCode, instr.Operand as MethodInfo);
                break;
            case OperandType.InlineField:
                methodIl.Emit(instr.OpCode, instr.Operand as FieldInfo);
                break;
            case OperandType.InlineType:
                methodIl.Emit(instr.OpCode, instr.Operand as Type);
                break;
            case OperandType.InlineString:
                methodIl.Emit(instr.OpCode, instr.Operand as string);
                break;
            case OperandType.InlineI:
                methodIl.Emit(instr.OpCode, (int)instr.Operand);
                break;
            case OperandType.InlineI8:
                methodIl.Emit(instr.OpCode, (long)instr.Operand);
                break;
            case OperandType.InlineR:
                methodIl.Emit(instr.OpCode, (double)instr.Operand);
                break;
            case OperandType.InlineNone:
                methodIl.Emit(instr.OpCode);
                break;
            // 其他操作数类型可根据实际需求补充
            default:
                throw new NotSupportedException($"不支持的操作数类型: {instr.OpCode.OperandType}");
        }
    }

    // 在父IL生成器中调用这个动态生成的包装方法
    parentIlGenerator.Emit(OpCodes.Call, wrappedMethod);
}

3. 关键注意事项

  • 闭包处理:如果原委托是捕获了外部变量的Lambda表达式,直接复制IL会失败(闭包字段属于原类型,动态类型无法访问)。此时需要:
    1. 将原闭包类型的字段复制到动态TypeBuilder中;
    2. 修改IL指令中的字段引用,指向新生成的字段;
    3. 若原方法是实例方法,需将实例对象作为参数传入动态方法。
  • 程序集依赖配置:创建动态程序集时,确保使用正确的AssemblyBuilder配置,避免System.Private.CoreLib找不到的问题:
    var assemblyName = new AssemblyName("MyDynamicAssembly");
    var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
    var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name, $"{assemblyName.Name}.dll");
    var typeBuilder = moduleBuilder.DefineType("MyDynamicType", TypeAttributes.Public);
    

内容的提问来源于stack exchange,提问作者Noraa Junker-Wildi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 12:25:20