【问题标题】:How to remove the last few segments of Emit IL at runtime如何在运行时删除 Emit IL 的最后几段
【发布时间】:2019-09-25 08:27:32
【问题描述】:

如何在运行时移除 Emit IL 的最后几段

我尝试修改一千行代码中的一些逻辑,我想用回滚IL的方式添加新的逻辑,避免改变之前的代码。

简单例如:

我希望在isSomeLogic 为真时删除 Emit IL 的最后几段,然后发出新的 il。

void Main()
{
    DynamicMethod methodbuilder = new DynamicMethod("Deserialize" + Guid.NewGuid().ToString(), typeof(void), null);
    var il = methodbuilder.GetILGenerator();
    il.Emit(OpCodes.Ldstr, "Hello World");
    Type[] types = new Type[1]{typeof(string)};
    MethodInfo method = typeof(Console).GetMethod("WriteLine", types);
    il.Emit(OpCodes.Call, method);
    il.Emit(OpCodes.Ret);

    // do some thing...
    var isSomeLogic = true;
    if( isSomeLogic ){
        //remove the il OpCodes.Ret and add new logic Emit
        il.Emit(OpCodes.Ret);
    }

    var func = (Action)methodbuilder.CreateDelegate(typeof(Action));
    func();
}

【问题讨论】:

  • 既然这显然是在运行时发出的,为什么不推迟 OpCodes.Ret 发出,直到你知道是否要在返回之前发出更多代码?
  • 谢谢,一千行代码尝试修改一些逻辑,想用回滚IL的方式添加新的逻辑,避免改动之前的代码。

标签: c# cil emit


【解决方案1】:

ILGenerator 仅用于转发。您无法删除您已添加的操作码。相反,只是...不添加它们?或者,您可以使用Label 和跳转操作; Ret 不需要位于方法的end;以下是完全有效的,只要堆栈在 ret 处处于正确的高度,并且堆栈高度对于到特定位置的所有路径都是相同的。

  • 做事
  • 跳转到 X
  • 标签:是的
  • 做更多的事情
  • 回复
  • 标签:X
  • 做更多的事情
  • 跳转到Y

【讨论】:

  • 谢谢,稍后我将其标记为答案,并且我尝试在一千行代码中修改一些逻辑,我想使用回滚IL方式添加新逻辑,避免更改以前的代码。
  • @ITWeiHan 我的建议:更改之前的代码以使其适合场景; 无论如何,IL 很难做到正确;你最不想做的就是破解一些不太适合的东西;相信我:我去过那里(我做了“相当多”的 IL-emit)
  • 谢谢!我会用你的方式,我看过 Dapper IL 写的,真的很棒。
  • @ITWeiHan Dapper 的 IL 写作坦率地说是粗糙且结构糟糕;我很想把它撕下来重新开始; protobuf-net 有更多更合理的发射
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-11-21
  • 2023-03-12
  • 1970-01-01
  • 1970-01-01
  • 2011-06-17
  • 2012-06-16
  • 2017-11-28
相关资源
最近更新 更多