c# – Reflection.Emit.ILGenerator异常处理“Leave”指令

前端之家收集整理的这篇文章主要介绍了c# – Reflection.Emit.ILGenerator异常处理“Leave”指令前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
首先,一些背景信息:

我正在为一个学校项目编写一个编译器.它已经在运行,我花费了大量的精力来修复和/或优化它.最近遇到一个问题是我发现当您调用以下任何成员方法时,ILGenerator对象会生成一个额外的休假指令:

BeginCatchBlock()
BeginExceptFilterBlock()
BeginFaultBlock()
BeginFinallyBlock()
EndExceptionBlock()

所以,通过调用BeginExceptionBlock()来启动一个try语句,用BeginCatchBlock()添加一些catch子句,可以用BeginFinallyBlock()添加一个finally子句,然后用EndExceptionBlock()结束受保护的代码区域.

我列出的方法自动生成一条在try语句之后分支到第一条指令的leave指令.我不想要这些,有两个原因.一个,因为它总是生成一个未优化的休假指令,而不是一个leave.s指令,即使它的分支只有两个字节.另外两个,因为你不能控制休假指令的位置.

所以,如果你想分支到你的代码中的其他位置,你必须添加一个编译器生成的本地变量,根据你想要进入try语句的位置来设置它,让EndExceptionBlock()自动生成leave指令,然后在try块下面生成一个switch语句.或者,您可以在调用之前的方法之前自己发出leave或leave.s指令,导致一个丑陋和不可访问的额外5个字节,如下所示:

L_00ca: leave.s L_00e5
L_00cc: leave L_00d1

这两个选项都是我不能接受的.有没有办法阻止自动生成假指示,还是以其他方式指定保护区,而不是使用这些方法(这是非常烦人的,实际上没有记录的)?

编辑
注意:C#编译器本身就是这样做的,所以它不像有一个很好的理由强迫我们.例如,如果您有.NET 4.5 beta,请反汇编以下代码并检查其实现:(内部添加异常块)

public static async Task<bool> TestAsync(int ms)
{
    var local = ms / 1000;
    Console.WriteLine("In async call,before await " + local.ToString() + "-second delay.");
    await System.Threading.Tasks.Task.Delay(ms);
    Console.WriteLine("In async call,after await " + local.ToString() + "-second delay.");

    Console.WriteLine();
    Console.WriteLine("Press any key to continue.");
    Console.ReadKey(false);
    return true;
}

解决方法

据我所知,您无法在.NET 4.0中执行此操作.使用ILGenerator创建方法体的唯一方法是使用MethodBuilder.CreateMethodBody,但不允许您设置异常处理信息.而ILGenerator强制您所要求的休假指示.

但是,如果.NET 4.5是您的选项(似乎是),请查看MethodBuilder.SetMethodBody.这允许您自己创建IL,但仍然通过异常处理信息.您可以将其包装在您自己的自定义ILGenerator类中,Emit方法使用OpCode参数,并读取OpCode.Size和OpCode.Value以获取相应的字节.

当然,总是有Mono.Cecil,但是这可能需要对您已经编写的代码进行更广泛的更改.

编辑:you appear to have already figured this out yourself,但是你把这个问题放开了.您可以发布自己的问题的答案,并接受他们,如果你自己弄清楚了.这样可以让我知道我不应该浪费时间搜寻,而让其他同样问题的人知道该怎么做.

猜你在找的C#相关文章