c# - try-catch 在 IL 中如何工作?

标签 c# .net-core cil

考虑这段代码:

void Main()
{
    try {
        Console.Write("try ");
        throw new NotImplementedException();
    } 
    catch (NotImplementedException) {
        Console.Write("catch");
    }
}

使用 LINQPad,我看到代码编译为:

IL_0000:  nop         
IL_0001:  nop         
IL_0002:  ldstr       "try"
IL_0007:  call        System.Console.WriteLine
IL_000C:  nop         
IL_000D:  newobj      System.NotImplementedException..ctor
IL_0012:  throw       
IL_0013:  pop         
IL_0014:  nop         
IL_0015:  ldstr       "catch"
IL_001A:  call        System.Console.WriteLine
IL_001F:  nop         
IL_0020:  nop         
IL_0021:  leave.s

上面的代码打印try catch,如果我抛出Exception,则打印try并且程序由于未处理的异常而退出(正如预期的那样),IL 代码保持不变,除了这一行:

IL_000D:  newobj      System.Exception..ctor

这背后的逻辑是什么? 我会排除检查异常类型以决定是否进入 catch block 的逻辑。

最佳答案

我这里有点死灵法术。我花了几个小时阅读有关该主题的规范,这里有一些评论中未涵盖的有趣细节。 引号取自 Standard ECMA-335 - Common Language Infrastructure (CLI) :

Each method in an executable has associated with it a (possibly empty) array of exception handling information. Each entry in the array describes a protected block, its filter, and its handler. When an exception occurs, the CLI searches the array for the first protected block that

  • 保护包括当前指令指针在内的区域
  • 谁的过滤器希望处理异常

If a match is not found in the current method, the calling method is searched, and so on. If no match is found the CLI will dump a stack trace and abort the program

一些需要注意的事情是:

  • 异常处理程序可以访问局部变量和局部内存池 捕获异常的例程,但计算堆栈上的任何中间结果 抛出异常时丢失
  • 描述异常的异常对象由 CLI 自动创建,并且 在进入过滤器或 catch 子句时作为第一项插入评估堆栈

所以“一个(可能为空的)异常处理信息数组”实际上是每个方法都有的一个部分

At the next 4-byte boundary following the method body can be extra method data sections. Currently, the method data sections are only used for exception tables.

该部分由 子句 组成,其中存储有关 try block 从何处开始、从何处结束、从何处开始 catch 的信息,并且有一个特定字段 - ClassToken 被描述为 Meta data token for a type-based exception handler 应该是有关异常类型的信息,可以由该特定 catch block 处理。

不幸的是,ILDASM 不显示原始方法头并从那里插入信息作为反汇编代码 View 中的 .try 指令,但 IL 本身没有异常类型处理的具体指令,因为它不为相同的目的插入特定的中间代码。

关于c# - try-catch 在 IL 中如何工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54536858/

相关文章:

c# - 如何让 View 模型的属性设置所有关联子控件的高度/宽度

c# - 使用动态表达式对组进行 IQueryable LINQ 转换错误

c# - 在 WPF 中鼠标悬停时如何更改组合框边框的颜色?

docker - 在 docker 容器内运行 dotnet 测试

mysql - 如何在 Entity Framework Core 中进行分组而不重复分组?

c# - 可以获取 C# Delegate 的 MSIL 吗?

c# - 我们需要 C# 中的定点组合器吗?

.net-core - 如何使用 dotnet CLI 将 EmbeddedResource 添加到项目中?

c# - 如何防止我的代码被盗?

c# - C# 中的 IL Return 返回错误值