【问题标题】:What is a better way to modify IL code of the method?修改方法的IL代码的更好方法是什么?
【发布时间】:2016-12-13 07:39:53
【问题描述】:

我需要将方法A()中的call指令从this.B()替换为this.C()。现在我使用this helper 获取方法A() 的IL 指令,然后替换call 指令,然后使用IL 生成器手动发出所有指令。 注意:该助手有一个 nuget - Mono.Reflection

部分代码演示我需要什么:

var emitter = methodBuilder.GetILGenerator();
foreach (var cmd in baseMethodInfo.GetInstructions())
{
    if (cmd.Operand == null)
        emitter.Emit(cmd.OpCode);
    else
    {
        switch (cmd.OpCode.OperandType)
        {
            case OperandType.InlineMethod:
            {
                var currentMethodInfo = cmd.Operand as MethodInfo;
                //check that it's this.B() and get this.C() then
                var methodToReplace = installedMethods.SingleOrDefault(m => m.MethodInfo == currentMethodInfo);
                if (methodToReplace != null)
                    emitter.EmitCall(cmd.OpCode, methodToReplace.MethodBuilder, null);
                else
                    emitter.EmitCall(cmd.OpCode, currentMethodInfo, null);
                break;
            }
            ...
        }
    }
}

但我猜有人已经实现了类似的东西,我想使用它,因为它很可能是一种更好、更安全的方式。我知道 Mono.Cecil 可以替换指令,但我知道它只适用于 asembly loading time,但我需要 runtime

【问题讨论】:

  • 为什么需要“运行时”?看起来你无论如何都在创建一个新方法,你不能使用 Cecil 创建一个只包含你需要的方法的新程序集吗?
  • 不幸的是,我得到了有关应该在运行时替换哪些方法的信息。 this.B()this.C() 只是一个例子。
  • 为什么这是个问题?您可以在运行时创建并加载程序集。
  • 可能的性能问题。在我替换需要生成的代码的每个地方(在不同的方法中相同),保存和加载程序集。使用反射.emit 我可以声明一个程序集。但我没有考虑建议的方式。我可以尝试一下并测试性能。谢谢。
  • 程序集加载时间运行时。如果您在程序集加载后尝试这样做,那么您很可能为时已晚,必须在即时编译器从 IL 生成机器代码之前完成。

标签: c# code-generation reflection.emit


【解决方案1】:

与 Cecil 一起做是最简单的方法。正如 svick 所写,即使您需要替换的方法的信息在运行时出现(当然只要此方法满足您的性能要求),您也可以这样做。

但是如果您想查看其他选项,请查看this answer

【讨论】:

    猜你喜欢
    • 2014-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-26
    • 1970-01-01
    • 1970-01-01
    • 2021-06-08
    相关资源
    最近更新 更多