异常处理
大约 4 分钟
概念
异常是在程序执行期间出现的问题。在 C# 中,异常是对程序运行时出现的特殊情况的一种响应,例如尝试除以零、访问空引用等。异常提供了一种把程序控制权从某个部分转移到另一个部分的方式。
- 异常(Exception):是在程序执行期间发生的特殊情况,通常表示一个错误。
- 抛出异常(Throwing an Exception):当程序中出现异常情况时,系统或开发者可以通过抛出异常的方式来表示。
- 捕获异常(Catching an Exception):通过特定的代码结构来捕获并处理异常,防止程序异常终止。
异常处理
C# 使用 try
、catch
、finally
和 throw
语句来处理异常。
try
try
块包含可能引发异常的代码。如果在 try
块内的代码抛出了异常,控制将转移到紧随其后的 catch
块。
try
块后跟一个或多个catch
块。
try
{
// 可能引发异常的代码
}
catch
catch
块用于捕获并处理 try
块中抛出的异常。可以有多个 catch
块来捕获不同类型的异常。
catch (ExceptionType1 ex)
{
// 处理 ExceptionType1 类型的异常
}
catch (ExceptionType2 ex)
{
// 处理 ExceptionType2 类型的异常
}
finally
finally
块用于执行给定的语句,不管异常是否被抛出都会执行,通常用于资源的清理工作。例如打开一个文件,不管是否出现异常文件都要被关闭。
finally
{
// 清理代码,总是执行
}
throw
当问题出现时,程序抛出一个异常。使用 throw
关键字来完成。
throw new ExceptionType("异常信息");
示例
class Program
{
static void Main(string[] args)
{
try
{
int divisor = 0;
int result = Divide(10, divisor);
Console.WriteLine("结果是: " + result);
}
catch (DivideByZeroException ex)
{
Console.WriteLine("捕获到异常: " + ex.Message);
}
catch (Exception ex)
{
Console.WriteLine("捕获到一个未知异常: " + ex.Message);
}
finally
{
Console.WriteLine("执行 finally 块,无论是否有异常。");
}
}
static int Divide(int numerator, int denominator)
{
if (denominator == 0)
{
throw new DivideByZeroException("除数不能为零。");
}
return numerator / denominator;
}
}
运行结果:
捕获到异常: 除数不能为零。
执行 finally 块,无论是否有异常。
自定义异常
除了使用 .NET 提供的异常类之外,你还可以通过继承 System.Exception
类或它的子类来创建自定义异常,可以提供更多的错误信息,使错误处理更加精确和方便。
创建自定义异常的步骤:
- 继承
Exception
类:自定义异常类应该继承自System.Exception
类或其派生类。 - 提供标准构造函数:为了与 .NET 异常管理机制兼容,应提供四个标准的构造函数。
- 无参数构造函数
- 带有错误消息字符串的构造函数
- 带有错误消息和内部异常的构造函数,用于异常链
- 一个用于序列化的构造函数,支持异常的序列化和反序列化
- 添加自定义属性(可选):可以添加自定义属性来提供额外的错误信息。
using System;
// 自定义异常类
public class MyCustomException : Exception
{
// 无参数构造函数
public MyCustomException() : base() {}
// 带有错误消息的构造函数
public MyCustomException(string message) : base(message) {}
// 带有错误消息和内部异常的构造函数
public MyCustomException(string message, Exception innerException) :
base(message, innerException) {}
// 可以添加自定义属性或方法
}
// 使用自定义异常
class Program
{
static void Main()
{
try
{
// 触发自定义异常
throw new MyCustomException("这是一个自定义异常");
}
catch (MyCustomException ex)
{
Console.WriteLine($"捕获到自定义异常: {ex.Message}");
}
}
}
为什么使用自定义异常?
- 提高代码可读性:通过自定义异常的名称,可以更清晰地表达错误的类型。
- 统一异常处理:可以将相似的错误情况归类到同一类型的自定义异常下,便于统一处理。
- 增强错误信息:通过自定义属性和方法,可以提供比标准异常更丰富的错误信息,帮助开发者快速定位和解决问题。
自定义异常是 C# 异常处理机制的一个重要组成部分,合理使用可以极大提高应用程序的健壮性和可维护性。
最佳实践
- 尽量具体地捕获异常:应该尽量捕获具体的异常类型,而不是捕获所有异常的基类
Exception
。 - 不要滥用异常:只在真正的异常情况下使用异常处理机制,不要用它来控制程序的正常流程。
- 在适当的层次处理异常:应该在能够恰当处理异常的代码层次捕获异常,不要无谓地传递异常。