异常处理,我们写的代码里经常会用到:try{}catch{}finally{}。可是大家真的了解它吗?

下面的代码,运行结果是什么?大家猜一下:

View Code

static class Program
    {

static void Main(string[] args)
        {
            Console.WriteLine(Program.MethodC());
            Program.MethodB();
            Console.ReadLine();
        }

static void MethodA()
        {
            try
            {
                throw new NullReferenceException();
            }
            catch (IndexOutOfRangeException)
            {
                throw;
            }
            finally
            {
                Console.WriteLine("MethodA finally");
            }
        }

static void MethodB()
        {
            try
            {
                MethodA();
            }
            catch (NullReferenceException)
            {
                Console.WriteLine("MethodB catch");
            }
            finally
            {
                Console.WriteLine("MethodB finally");
            }
        }

static int i = 1;
        static int MethodC()
        {
            try
            {
                Console.WriteLine("MethodC try");
                return i;
            }
            finally
            {
                i = 2;
                Console.WriteLine("MethodC finally");
                Console.WriteLine("MethodC:"+i);
            }
        }

下面给出运行结果:

View Code

MethodC try
MethodC finally
MethodC:2
1
MethodA finally
MethodB catch
MethodB finally

看上面的运行结果,语句:Console.WriteLine(Program.MethodC())的输出为:

MethodC try
MethodC finally
MethodC:2
1

MethodC方法,主要考察的有二点,一是finally语句和return语句执行的先后顺序,二是finally语句是否可以改变return语句中返回的值。
第一点大家都知道,return前finally总是会执行,第二点就有些模糊了,运行结果也跟最初自己猜的不同。我们看一下MethodC方法生成的IL代码:

.method private hidebysig static int32  MethodC() cil managed
{
  // Code size       70 (0x46)
  .maxstack  2
  .locals init (int32 V_0)
  IL_0000:  nop
  .try
  {
    IL_0001:  nop
    IL_0002:  ldstr      "MethodC try"
    IL_0007:  call       void [mscorlib]System.Console::WriteLine(string)
    IL_000c:  nop
    IL_000d:  ldsfld     int32 ConsoleApplication.Program::i  //将静态字段Program.i压入栈中
    IL_0012:  stloc.0  //从栈中取出值(就是刚压入的i),放到"第0号"临时变量中
    IL_0013:  leave.s    IL_0043  //这里会退出try区块,转向IL_0043
  }  // end .try
  finally
  {
    IL_0015:  nop
    IL_0016:  ldc.i4.2  //在栈中放入一个4byte的数,值为2
    IL_0017:  stsfld     int32 ConsoleApplication.Program::i  //从栈中获取值(刚放入的2),修改i
    IL_001c:  ldstr      "MethodC finally"
    IL_0021:  call       void [mscorlib]System.Console::WriteLine(string)
    IL_0026:  nop
    IL_0027:  ldstr      "MethodC:"
    IL_002c:  ldsfld     int32 ConsoleApplication.Program::i
    IL_0031:  box        [mscorlib]System.Int32
    IL_0036:  call       string [mscorlib]System.String::Concat(object,
                                                                object)
    IL_003b:  call       void [mscorlib]System.Console::WriteLine(string)
    IL_0040:  nop
    IL_0041:  nop
    IL_0042:  endfinally
  }  // end handler
  IL_0043:  nop
  IL_0044:  ldloc.0  //将"第0号"临时变量的值压入栈中
  IL_0045:  ret  //退出方法,返回值
} // end of method Program::MethodC

  注意红色字体部分,绿色注释是我添加的,从上面IL及注释可以了解到,在MethodC方法里,会有一个隐式的”第0号“变量,来临时保存return的值,所以finally中语句虽然修改了Program.i的值,但是MethodC方法的返回值是不因finally语句而变化。

Program.MethodB(); 的输出结果,没什么好说的,大家应该都可以准确的说出来,这里只引用CLR VIA C#上一段话将try catch 语句的执行顺序简单介绍一下:

在try块中的代码(或者从try块调用的任何方法)抛出一个异常,CLR将搜索捕捉类型与抛出的异常相同(或是它的基类)的catch块。如果没有任何捕捉类型与抛出的异常匹配,CLR会去调用栈的更高一层搜索一个与异常匹配的捕捉类型。如果到了调用栈的顶部,还是没有找到具有匹配捕捉类型的一个catch块,就会发成一个未处理的异常。
  一旦CLR找到一个具有匹配捕捉类型的catch块,就会执行内层所有finally块中的代码。所谓“内层finally块”是指从抛出异常的try块开始,到匹配异常的catch块之间的所有finally块。这里注意匹配异常的那个catch块所关联的finally块尚未执行,该finally块的代码一直要等到这个catch块中的代码执行完毕之后才执行。

转载于:https://www.cnblogs.com/kdalan/archive/2012/06/06/2537498.html

一道异常处理执行顺序面试题的简单分析相关推荐

  1. Promise和setTimeout执行顺序 面试题

    看到过下面这样一道题: (function test() {setTimeout(function() {console.log(4)}, 0);new Promise(function execut ...

  2. 对一道if-else相关的程序题的简单分析

    今天同事在微信群里提出了一个问题,看似是一个面试题. 大体的意思就是补充下面if条件使得输出 Hello World if(){ System.out.print("Hello") ...

  3. JMeter基础之组件的作用域与执行顺序

    对于新手来说,jmeter的元件是还是不少的,如果我们按照每一个元件的每一个参数的含义去学习,无疑会降低性能测试学习的热情,算我们熟悉了所有元件以及元件上的参数了,我们也不知道如何将其组合成我们想要描 ...

  4. for循环的执行顺序(案例+详解)

    案例分析 #include <stdio.h> #include <srdlib.h> int main(void) { char c; for(c=getchar();get ...

  5. 【Spring Boot入门】AOP基础及Advice的执行顺序

    本文主要分为两个部分,首先介绍AOP的基础,包括为什么要使用AOP以及AOP中的基本概念,然后讲解AOP中各类Advice的执行顺序并给出简单示例. 一.AOP基础 1.为什么要使用AOP AOP(A ...

  6. 【虫师--系列】JMeter基础之--元件的作用域与执行顺序

    来自: http://www.cnblogs.com/fnng/archive/2012/12/27/2836506.html    作者:虫师 前面有介绍过jmeter的元件类别,对于新手来说,jm ...

  7. 6.2 jmeter基础—元件执行顺序

    4.3.元素的执行顺序 1 配置元件 Configuration elements 2 前置处理器Pre-Processors 3 定时器Timers 4 取样器Sampler 5 后置处理器Post ...

  8. 多个for语句嵌套执行顺序_阿里真实面试题解析之实现多个线程顺序执行的几种方式...

    前几天有一位同事在阿里一面的时候被问到这么一个多线程问题:如何保证多个线程的顺序执行.当时他没有回答上来,所以为了避免大家以后遇到同样的面试题还是回答不上来,今天我们就来分析解答下这个问题. 问题缘由 ...

  9. go语言错误和异常处理,panic、defer、recover的执行顺序

    一.panic()和recover() Golang中引入两个内置函数panic和recover来触发和终止异常处理流程,同时引入关键字defer来延迟执行defer后面的函数. 一直等到包含defe ...

最新文章

  1. Acwing第 17 场周赛【完结】
  2. SAP Spartacus 4.0 版本因为 hamburger 依赖导致构建出错的问题
  3. console.log 用法
  4. java顺序表增删查改_Java实现顺序表的增删改查
  5. mysql 汉字笔画排序规则_SQL Server 与MySQL中排序规则与字符集相关知识的一点总结...
  6. 也谈说话这件事--《好好说话》读后感
  7. Linux IP 地址修改
  8. 计算机原理形考3,计算机组成原理A形考作业3参考解答
  9. Java好学吗,我们怎么才能学好Java
  10. 亿级数据服务平台:跟低效率、指标难统一的数仓说再见!
  11. 2016百度之星 - 测试赛(热身,陈题)1001,1002,1003,1004
  12. Navicat SQL server 数据备份,数据还原
  13. Java 中Calendar日历类的基本使用
  14. 74LS175D四人抢答器设计
  15. C语言学习--求圆面积和求正方体的体积 ,平均数---2022.9.3
  16. Kubernetes CKS【10】---Cluster Hardening - Restrict API Access
  17. 全国省市区三级城市联动下来选项select插件
  18. 怎么将语音转为文字?不如试试这几个语音转文字软件app
  19. Powerpoint快捷键大全
  20. 12月末总结--小琐事

热门文章

  1. 【面向对象】第一单元总结——表达式求导
  2. ROS学习笔记三:编写第一个ROS节点程序
  3. 【洛谷5251】[LnOI2019] 第二代图灵机(线段树+ODT)
  4. html页面表格导出到excel总结
  5. [转载 整理]C语言链表实例
  6. javascript中错误使用var造成undefined
  7. 七种与輻射和平相處的妙法 - 生活至上,美容至尚!
  8. 访问IIS元数据库失败
  9. 什么是动态语言(转)
  10. 「SNOI2019」