Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/visual-studio-2012/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Reflection.Emit.ILGenerator异常处理“;“离开”;指示_C#_Cil_Reflection.emit - Fatal编程技术网

C# Reflection.Emit.ILGenerator异常处理“;“离开”;指示

C# Reflection.Emit.ILGenerator异常处理“;“离开”;指示,c#,cil,reflection.emit,C#,Cil,Reflection.emit,首先,一些背景信息: 我正在为一个学校项目做一个编译器。它已经开始工作了,我花了很多精力来修复和/或优化它。我最近遇到的一个问题是,我发现ILGenerator对象在调用以下任何成员方法时会生成额外的leave指令: BeginCatchBlock() BeginExceptFilterBlock() BeginFaultBlock() BeginFinallyBlock() EndExceptionBlock() 因此,您可以通过调用beginceptionblock()启动一个try语句,

首先,一些背景信息:

我正在为一个学校项目做一个编译器。它已经开始工作了,我花了很多精力来修复和/或优化它。我最近遇到的一个问题是,我发现ILGenerator对象在调用以下任何成员方法时会生成额外的
leave
指令:

BeginCatchBlock()
BeginExceptFilterBlock()
BeginFaultBlock()
BeginFinallyBlock()
EndExceptionBlock()
因此,您可以通过调用
beginceptionblock()
启动一个try语句,使用
BeginCatchBlock()
添加两个catch子句,可能使用
BeginFinallyBlock()
添加一个finally子句,然后使用
EndExceptionBlock()
结束受保护的代码区域

我列出的方法自动生成一个
leave
指令分支到try语句后的第一条指令。我不想要这些,有两个原因。第一,因为它总是生成一条未优化的
leave
指令,而不是
leave.s
指令,即使它只分支了两个字节。第二,因为你无法控制离开指令的去向

因此,如果您希望分支到代码中的其他位置,则必须添加编译器生成的局部变量,根据try语句的内部位置进行设置,让
EndExceptionBlock()
自动生成
leave
指令,然后在try块下方生成switch语句。或者,在调用前面的方法之一之前,您可以自己发出一条
leave
leave.s
指令,从而产生一个难看且无法访问的额外5字节,如下所示:

L_00ca: leave.s L_00e5
L_00cc: leave L_00d1
这两种选择我都不能接受。是否有任何方法可以防止自动生成
leave
指令,或者有任何其他方法可以指定受保护区域,而不是使用这些方法(这些方法非常烦人,实际上没有文档记录)

编辑 注意:C#编译器本身就是这样做的,因此似乎没有什么好的理由将其强加给我们。例如,如果您有.NET 4.5 beta版,请反汇编以下代码并检查其实现:(内部添加了异常块)

公共静态异步任务TestAsync(int-ms)
{
局部变量=ms/1000;
WriteLine(“在异步调用中,在等待“+local.ToString()+”-秒延迟之前”);
等待系统。线程。任务。任务。延迟(毫秒);
WriteLine(“在异步调用中,在等待“+local.ToString()+”-秒延迟”之后);
Console.WriteLine();
Console.WriteLine(“按任意键继续”);
Console.ReadKey(false);
返回true;
}

据我所知,在.NET 4.0中您无法做到这一点。不使用
ILGenerator
创建方法体的唯一方法是使用
MethodBuilder.CreateMethodBody
,但这不允许您设置异常处理信息。并且,
ILGenerator
强制执行您所询问的
离开
指令

但是,如果.NET4.5是您的一个选择(似乎是),请查看。这允许您自己创建IL,但仍然传递异常处理信息。您可以将其封装在自己的自定义类中,使用
Emit
方法获取
OpCode
参数,并读取
OpCode.Size
OpCode.Value
以获取相应的字节

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


编辑:,但您没有回答这个问题。你可以发布自己问题的答案并接受它们,如果你自己已经找到答案的话。这会让我知道我不应该浪费时间搜索,也会让其他有同样问题的人知道该怎么做。

谢谢你的回答。我没有打开它,因为我不确定我找到的解决方案(MethodBuilder.SetMethodBody)是否真的适合我——它没有非常描述性的文档。再次感谢!
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;
}