zoukankan      html  css  js  c++  java
  • 第二节 异常处理机制

    本节将介绍异常处理的机制,以及进行异常处理所需的C#构造。但是,这里不准备过多的讨论细节。本章旨在提供一些在代码中何时以及如何使用使用异常处理的指导原则。想要更多的了解异常处理机制和相关的C#语言构造,请参见.NET FrameWork文档和C#语言规范。另外,.NET Framework异常处理机制是用Windows提供的结构化异常处理机制构建的。

    以下C#代码展示了异常处理机制的标志用法,可通过它对异常处理代码块以及用途产生一个初步的认识。代码后面的各小节将正式描述try、catch、finally块及其用途,并提供关于他们的一些注意事项。

             try
                {
                    //需要得体的进行清除和恢复的代码放在这里
                }
                catch (InvalidOperationException)
                {
                    //从InvalidOperationException恢复的代码。
                }
                catch (IOException)
                {
                    //从IOException恢复的代码
                }
                catch
                {
                    //除了上诉异常之外的其他异常恢复的代码放在这里。
                    //捕捉任何异常时,通常要重新抛出异常。
                    throw;
                }
                finally
                {
    
                }        
    

      

    这段代码演示了使用各种异常处理块的一种可能的方式。不要被这些代码吓着,大多数方法只有一个try块和一个匹配的finally块,或者一个try块和一个匹配的catch块。

    1. Try 块

    Try块包含的代码通常要执行一些通用的资源清理操作,或者需要从异常中恢复,或者两者都需要,清理代码应该放在finally块中。Try块还可包含也许会抛出异常的代码。异常恢复代码应该放在一个或多个catch块中。针对应用程序能从中安全恢复的每一种异常,都应该创建一个catch块。一个try块至少要有一个关联的catch块或finally块,单独一个try块时没有意义的,c#也不允许。

    重要提示:开发人员有时不知道应该在一个try块中放入多少代码,这具体要取决于状态管理。如果一个try块中执行多个可能抛出同一个异常类型的操作,但不同的操作有不同的异步恢复措施,就应该将每个操作都放到自己的try中,这样才能正确的恢复状态。

    1. catch块

    catch块包含的是响应一个异需要执行的代码。一个try块可以关联0个或多个catch块。如果try块中的代码没有造成异常的抛出,CLR永远不会执行它的任何catch块中的代码。线程将跳过所有catch块,直接执行finally块中的代码。Finally块中的代码执行完毕后,执行从finally块后面的语句继续。

    Catch关键字后的圆括号中的表达式成为捕捉类型。在C#中,必须将捕捉类型指定为System.Exception或者它的一个派生类型。例如,上诉代码包含了用于处理异常的InvalidOperationException异常和IOException异常的catch块。最后一个catch块没有指定捕捉异常类型,它能处理除了前面的catch块指定之外的其他任何异常;这就相当于捕捉System.Exception的一个catch块(只是不能通过大括号中的代码访问异常信息)。

    CLR自上到下搜索一个匹配的catch块,所以应该将较具体的异常放到顶部。也就是说,首先出现的是派生程度最大的异常类型,接着是他们的基类型,最后是System.Exception(或者没有指定捕捉类型的catch块)。事实上,如果弄饭了这个顺序,将较具体的catch块放到靠近底部的位置,C#编译器会生成一个错误,因为这样catch块是不可达的。

    如果在try块中的代码抛出一个异常,CLR将搜索捕捉类型与抛出的异常相同的catch块。如果没有任何捕捉类型与抛出的异常匹配,CLR会调用栈的更高一层搜索一个与异常匹配的捕捉类型。如果都到了调用栈的顶部,还没有找到具有匹配捕捉类型的一个catch块,就会发生一个未处理的异常。

    一旦CLR找到一个具有匹配捕捉类型的catch块,就会执行内层所有finally块中的代码。所谓“内层finally块”是指从抛出异常的try块开始,到匹配异常的catch块之间的所有finally块。注意,匹配异常的那个catch块所关联的finally块尚未执行,该finally块中的代码一直要等到这个catch块中的代码执行完毕之后才会执行。

    所有内层finally块执行完毕之后,匹配异常的那个catch块中的代码才开始执行。Catch块中的代码通常执行一些对异常进行处理的操作。在catch块的末尾,我们有一下三个选择。

    1      .重新抛出异常,向调用栈更高一层的代码通知该异常的发生。

    2.抛出一个不同的异常,向调用栈高一层的代码提供更丰富的异常信息。

    3.让线程从catch块的底部退出。

    本章稍后针对每一种技术的使用时机提供一些指导方案。如果选择使用前两种技术,将抛出一个异常,CLR的行为将和以前说过的一样;回溯调用栈,查找捕捉类型和抛出的异常的类型匹配的catch块。

    如果选择最后一种技术,当线程从catch块的底部退出后,它将立即执行包含了finally块中的代码。Finally中的所有代码执行完毕后,线程退出finally块,执行紧跟在finally块之后的语句。如果不存在finally块,线程将从最后一个catch块之后的语句开始执行。

    C#允许在捕捉后指定一个变量。捕捉到一个异常时,该变量将引用抛出的这个System.Exception派生对象。Catch块的代码可通过引用该变量来访问异常的具体信息。

    尽管这个异常可以修改,但最好不要这么做,而应把它当成只读的。

    注意: 你的代码可像AppDomain的FirstChanceException事件登记。这样一来,只要AppDomain中发生一个异常,就会收到通知。这个通知是CLR搜索任何catch块之前发生的。

    1. finally块

    finally块包含的代码时保证会执行的代码。通常,finally块的代码执行的try块中的行动所要求的资源清理操作。

    例如,在一个try块中打开了一个文件,就应该将关闭文件的代码放到finally块中。

            private void ReadData(String pathname)
            {
                FileStream fs = null;
                try
                {
                    fs = new FileStream(pathname, FileMode.Open);
                }
                catch (IOException)
                {
                }
                finally
                {
                    if (fs != null) fs.Close();
                }
            }
    

      

    在上诉代码中,如果try块中的代码没有抛出异常,文件保证会被关闭。如果try块中的代码抛出了异常,文件也保证会被关闭,无论该异常是否被捕捉到。将关闭文件的语句放在finally块之后是不正确的,因为假如异常抛出但未被捕捉到。该语句执行不到,造成文件保持打开状态。

    try块并非一定关联一个finally块;有的时候,try块中的代码并不需要任何清理工作。但是,如果有finally块,它必须出现在所有catch块之后,而且一个try块最多只能关联一个finally块。线程执行完finally块中的代码后,会执行紧跟在finally块之后的语句。记住,finally代码块中只是清理工作,这些代码只需要负责对try块中发起的操作进行清理。Catch和finally块中的代码应该非常短,而且要有非常高的效率。避免自己又抛出一个异常。一般情况下,这两种块中的代码只有一到两行。

    当然,(catch中的)异常恢复代码或者(finally中的)清理代码总是有可能失败并抛出一个异常的。不过,虽然有可能,但是可能性不大。而且如果要是真的发生了这种事情,通常意味着某个地方出现了严重的问题。很可能是某些状态在一个地方发生了损坏。如果catch或者finally中无意抛出一个异常,也并不是世界末日,CLR的异常机制仍会正常运转,好像异常实在finally块之后抛出的一样。但是,出现这种情况时,CLR不会记录对应的try块中抛出的第一个异常,关于第一个异常的所有信息都将丢失,这个新异常可能不会由你的代码处理,最终变成一个未处理的异常。在这种情况下,CLR会终止你的进程。这是一件好事,因为损坏的所有状态都会被撤销。向较于让应用程序继续运行,造成不可预测的结果以及可能的安全漏洞,这样处理要好的多!

  • 相关阅读:
    安装Kali Linux虚拟机02
    前端入门之——知识补充 day11
    套接字编程知识回顾01
    关于js中 document.body.scrollTop 不能返回正确值的原因
    前端入门之——后台管理页面布局 学习 day10
    前端入门之——jquery day9
    pickle序列化与反序列化 + eval说明
    json序列化与反序列化
    项目中日志输出常用的设置
    logging模块基础3
  • 原文地址:https://www.cnblogs.com/bingbinggui/p/4541891.html
Copyright © 2011-2022 走看看