捕获并包装异常
介绍
编写软件是一项复杂的工作,即使是最好的软件也经常会出现各种问题。有时问题是由糟糕的代码引起的;有时问题是由应用程序代码中未考虑到的糟糕用户输入引起的,例如,将年龄输入字段的值赋为 Julia。无论问题的原因是什么,最终结果都是应用程序无法按预期运行。
异常是程序中违反系统或应用程序约束的运行时错误,或者是程序正常执行期间不应发生的情况。可能的异常包括尝试连接到不再存在的数据库、程序尝试将数字除以零或打开损坏的 XML 文件。当发生这些情况时,系统会捕获错误并引发异常。
捕获异常
捕获异常是一种处理这些意外错误的方法,通过定义在抛出异常时运行的代码块来处理。此代码块称为异常处理程序。如果没有异常处理程序,您的应用程序将停止(崩溃)并向用户显示非常不友好的错误消息。异常处理的目的是使用以下一项或多项来响应异常:
- 向您的用户显示一个用户友好的消息。
- 记录有关异常的信息,以便支持团队可以解决。
- 采取一些纠正措施,让程序继续运行而不会崩溃。
异常处理使用try关键字来尝试可能不会成功的操作,当您认为合理时使用catch关键字来处理失败,然后使用 finally关键字来清理资源。
让我们来看一个例子。创建一个新的控制台应用程序并使用以下内容更新Program.cs :
using System;
namespace MyApp
{
class Program
{
static void Main(string[] args)
{
var calculator = new Calculator();
Console.WriteLine("Enter number");
int number = int.Parse(Console.ReadLine());
Console.WriteLine("Enter divisor");
int divisor = int.Parse(Console.ReadLine());
try
{
calculator.Divide(number, divisor);
}
catch (Exception ex)
{
Console.WriteLine("Oh no, Something is wrong");
Console.WriteLine(ex);
}
}
class Calculator
{
public int Divide(int number, int divisor)
{
return number / divisor;
}
}
}
}
上面的代码接受来自用户的数字和除数,并使用这些值调用Divide方法。我们保护第 19 行以防出现任何错误。如果try块内发生异常,应用程序将通过运行catch块内的代码来处理它。在 .NET 中,将数字除以零会导致DivideByZeroException。因此,如果我们以零作为除数运行应用程序,我们会在控制台中打印以下结果。
应用程序打印上述消息并正常退出,没有崩溃。您可以看到这是在运行除法运算时遇到的DivideByZeroException 。
捕获并包装异常
有时将原始异常包装成新类型的异常然后抛出该新类型的异常可能会有所帮助。这实际上使我们能够更改在调用堆栈中传播的新异常类型。如果更高级别的 catch 块没有明确处理异常,则此更改可能有助于向更高级别的应用程序阐明异常。一个有用的应用是,如果您正在开发一个供其他程序员使用的库,您的库可能会使用一些低级代码,而低级代码中遇到的异常可能难以由库用户处理。在这种情况下,我们可以捕获执行这些低级操作时发生的异常,并将它们包装成自定义异常或库用户或更高级别的代码可以理解和处理的其他异常类型。
继续我们之前的例子,假设我们认为 DivideByZeroException不够明确,我们无法处理,我们可以将其包装在另一个异常中,并将其传播到调用堆栈。让我们用以下代码更新Program.cs :
using System;
namespace MyApp
{
class Program
{
static void Main(string[] args)
{
var calculator = new Calculator();
Console.WriteLine("Enter number");
int number = int.Parse(Console.ReadLine());
Console.WriteLine("Enter divisor");
int divisor = int.Parse(Console.ReadLine());
try
{
calculator.Divide(number, divisor);
}
catch (ArithmeticException ex)
{
Console.WriteLine("Oh no, Something is wrong");
Console.WriteLine(ex);
}
}
class Calculator
{
public int Divide(int number, int divisor)
{
try
{
return number / divisor;
}
catch (DivideByZeroException ex)
{
//propage this error
throw new ArithmeticException("Can't divide by 0. Please use a different number as divisor", ex);
}
}
}
}
}
从上面的代码中,我们更改了第 21 行的 catch 块以处理ArithmeticException异常类型。我们将除法运算包装在Divide方法中的 try/catch 块中。在 catch 块中,我们捕获DivideByZeroException类型并将其包装在ArithmeticException类型中。包装异常只需设置新异常的InnerException属性以将调用堆栈向上传播到捕获的异常。这样做可以维护异常调用堆栈信息。
运行应用程序并在系统提示时输入除数零。抛出异常时应打印以下内容:
您可以看到捕获的异常是 ArithmeticException ,并且它具有定义的错误消息。来自调用堆栈的信息指向第 34 行,即发生错误的位置。
概括
当正在运行的应用程序中遇到错误时,会引发异常。发生异常时,程序会暂停正常执行,生成包含错误信息的异常对象,并将异常传播到调用堆栈。如果没有代码来捕获和处理异常,程序就会停止运行(即崩溃)。我们需要一个异常处理程序来捕获和处理异常。最后,我们研究了如何使用catch关键字以及如何包装异常,以便将更具体的异常传播到调用堆栈。
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~