异常处理

Posted home-wang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了异常处理相关的知识,希望对你有一定的参考价值。

异常处理

在C#中,所有的异常都是使用一个异常类型的实例对象表示,都继承自System.Exception类型,或者直接使用System.Exception类型的实例对象;位于finally块中的代码可以保证不管代码是正常结束,还是进入异常处理代码块,其中的语句均会被执行,finally语句中放置资源回收的代码是一个不错的主意;BCL都提供了预定义的异常类供使用,其使用方式和应用级别的异常处理完全相同。

异常类

System.Exception类是所有异常类的基类,其中:

  • Message:只读字符串,此属性为当前的异常提供了描述性信息
  • InnerException:只读属性,值不为null,则可以通过它的值获取当前异常的异常实例;如果其值为null,则表示当前异常不是由其他异常引发的
  • StackTrace:只读字符串,描述了调用堆栈的内容,其中首先显示最近的方法调用

为了区分系统级异常和应用级异常,BCL提供了两种直接继承自System.Exception的异常类型,System.SystemException和System.ApplicationException。因此我们编写的自定义异常应从ApplicationException继承。

抛出异常

public long Divide(int a, int b)

    try
    
        return a / b;
    
    catch (System.DivideByZeroException e)
    
        //抛出异常
        //如果有原始异常,推荐将原始异常传入
        throw new System.ArgumentException(“除数不能为0”, “b”, e);
    

捕获异常

处理异常时都按照从特定到最不特定(从具体到一般)的顺序对catch块中处理的异常进行排序,try/catch块有三种形式:try-catch、try-finally、try-catch-finally,不带catch或finally块的try语句将导致编译器错误。

try   //可能引发异常的代码
catch (System.ApplicationException e) {} //异常处理代码块,可以有多个
catch (System.SystemException e)         //顺序从具体到一般
finally   //不管是否发生异常,均会执行

当异常发生后,CLR首先会判断当前引发的是何种异常类型,例如:是DivideByZeroException还是ArgumentException,然后以从上至下的顺序,搜索与当前执行语句(且和具体的异常类型)最匹配的catch块。搜索会从当前方法开始,寻找方法是否包括于一个try/catch块内,如果有,就对catch进行匹配,如果没有就定位到调用当前方法并继续寻找,一直向上层继续,直到找到为止。

如果存在两个catch块,一个是捕获某个特定的异常,一个是捕获更加常规的异常,注意:

  • 捕获特定异常的匹配度要比捕获常规异常的匹配度高
  • 捕获特定类型的catch块和基类型的catch块同时存在,则前者要位于后者之前,否则无法通过编译
class OneException : ApplicationException 

class Program

    static void DoSomething()
    
        throw new OneException();
    

  static async Task Main(string[] args)
  
    try
    
        Program.DoSomething();
    
    catch (OneException e)
    
        //执行
        Console.WriteLine("OneException code");
    
    catch (ApplicationException e)
    
        //ApplicationException是OneException的基类,同时出现时必须放在它的后面,否则会编译错误
        Console.WriteLine("ApplicationException code");
    
    catch (SystemException e)
    
        Console.WriteLine("SystemException code");
    
    finally
    
        //执行
        Console.WriteLine("finally code");
    
  

一般来说,除非明确知道如何处理try块中可能引发的所有异常,或者catch块的末尾包括一条throw语句,否则请不要在catch块中指定Exception,

自定义的异常

自定义的异常应该从System.Application.Exception派生,创建时要注意:

  • 从System.Application.Exception和System.Exception派生
  • 使用Exception这个词作为自定义的异常名称为后缀
  • 至少提供三个公共构造函数(一个不包含参数的默认构造函数、一个可以包含异常消息的构造函数、一个可以包含异常消息,以及引发异常的异常引用的构造函数)

异常处理方法

  • 尽量先由程序自动处理异常,若不能则考虑使用友好的提示告知用户,并根据等级记录日志
  • 限定异常范围,尽量缩小异常处理范围,如果只需要检测某一行代码,就不要把整段代码都放进try语句中
  • 应该尽量在上层捕获并处理异常(全局异常处理),过多的下层处理会有性能损失

以上是关于异常处理的主要内容,如果未能解决你的问题,请参考以下文章

使用片段中的处理程序时出现非法状态异常

Java异常处理机制

java 反射代码片段

java.util.MissingResourceException: Can't find bundle for base name init, locale zh_CN问题的处理(代码片段

使用实体框架迁移时 SQL Server 连接抛出异常 - 添加代码片段

片段中的Android致命异常