什么时候该抛出异常,抛出什么异常?什么时候该捕获异常,捕获之后怎么处理异常?你可能已经使用异常一段时间了,但对 .NET/C# 的异常机制依然有一些疑惑。那么,可以阅读本文。
本文适用于已经入门 .NET/C# 开发,已经开始在实践中抛出和捕获异常,但是对 .NET 异常机制的用法以及原则比较模糊的小伙伴。通过阅读本文,小伙伴们可以迅速在项目中使用比较推荐的异常处理原则来处理异常。
本文内容
快速了解 .NET 的异常机制
Exception 类
捕捉异常
引发异常
创建自定义异常
finally
异常堆栈跟踪
异常处理原则
try-catch-finally
该不该引发异常?
该不该捕获异常?
应用程序全局处理异常
抛出哪些异常?
异常的分类
其他
AccessViolationException
FileNotFoundException
一些常见异常的原因和解决方法
捕捉非 CLS 异常
快速了解 .NET 的异常机制
Exception 类
我们大多数小伙伴可能更多的使用 Exception
的类型、Message
属性、StackTrace
以及内部异常来定位问题,但其实Exception
类型还有更多的信息可以用于辅助定位问题。
Message
用来描述异常原因的详细信息如果你捕捉到了异常,一般使用这段描述能知道发生的大致原因。
如果你准备抛出异常,在这个信息里面记录能帮助调试问题的详细文字信息。
StackTrace
包含用来确定错误位置的堆栈跟踪(当有调试信息如 PDB 时,这里就会包含源代码文件名和源代码行号)InnerException
包含内部异常信息Source
这个属性包含导致错误的应用程序或对象的名称Data
这是一个字典,可以存放基于键值的任意数据,帮助在异常信息中获得更多可以用于调试的数据HelpLink
这是一个 url,这个 url 里可以提供大量用于说明此异常原因的信息
如果你自己写一个自定义异常类,那么你可以在自定义的异常类中记录更多的信息。然而大多数情况下我们都考虑使用 .NET 中自带的异常类,因此可以充分利用 Exception
类中的已有属性在特殊情况下报告更详细的利于调试的异常信息。
捕捉异常
捕捉异常的基本语法是:
try
{
// 可能引发异常的代码。
}
catch (FileNotFoundException ex)
{
// 处理一种类型的异常。
}
catch (IOException ex)
{
// 处理另一种类的异常。
}
除此之外,还有 when
关键字用于筛选异常:
try
{
// 可能引发异常的代码。
}
catch (FileNotFoundException ex) when (Path.GetExtension(ex.FileName) is ".png")
{
// 处理一种类型的异常,并且此文件扩展名为 .png。
}
catch (FileNotFoundException ex)
{
// 处理一种类型的异常。
}
无论是否有带 when
关键字,都是前面的 catch
块匹配的时候执行匹配的 catch
块而无视后面可能也匹配的 catch
块。
如果 when
块中抛出异常,那么此异常将被忽略,when
中的表达式值视为 false
。有个但是,请看:.NET Framework 的 bug?try-catch-when 中如果 when 语句抛出异常,程序将彻底崩溃 - walterlv。
引发异常
引发异常使用 throw
关键字。只是注意如果要重新抛出异常,请使用 throw;