在 C# 中抛出并重新抛出异常
介绍
编写软件是一项复杂的工作,即使是最好的软件也经常会出现各种问题。有时问题是由糟糕的代码引起的;有时问题是由应用程序代码中未考虑到的错误用户输入引起的。无论问题的原因是什么,最终结果都是应用程序无法按预期运行。此时,我们说应用程序遇到了错误。在 .NET 中,当正在运行的应用程序遇到错误时会引发异常。
什么是异常?
异常是程序中违反系统或应用程序约束的运行时错误,或者是程序正常执行期间不应发生的情况。可能的异常包括当程序试图将数字除以零时尝试连接到不再存在的数据库或打开损坏的 XML 文件。当发生这些情况时,系统会捕获错误并引发异常。
抛出异常
当发生违反系统或应用程序约束的情况时,它可以生成异常以向调用者发出操作失败的信号。生成和发出错误信号的过程称为引发异常。这是使用throw关键字后跟从System.Exception派生的类的新实例来完成的。让我们看一个例子。创建一个新的控制台项目并使用以下代码更新Program.cs 。
using System;
namespace MyApp
{
class Program
{
static void Main(string[] args)
{
var radio = new Radio();
radio.SetVolume(120);
}
class Radio
{
public int Volume { get; set; }
public string Station { get; set; }
public void SetVolume(int volume)
{
if (volume > 100)
{
throw new ArgumentOutOfRangeException(nameof(volume), "volume cannot be more than 100");
}
Volume = volume;
}
public void SetStation(string station)
{
if (string.IsNullOrEmpty(station))
{
throw new ArgumentNullException(nameof(station), "you cannot tune to an empty station");
}
Station = station;
}
}
}
}
在上面的代码示例中,我们定义了一个Radio类、属性Station和Volume以及方法SetStation和SetVolume。当使用大于 100 的值调用SetVolume方法时,应用程序将抛出ArgumentOutOfRangeException,参数名称和异常消息作为参数。同样,当使用空字符串调用SetStation方法时,它将抛出ArgumentNullException,参数名称和异常消息作为参数。
如果我们运行应用程序并且它崩溃了,它将打印出异常消息,并且堆栈跟踪会告诉我们控制台中发生错误的位置。它给您的信息应该类似于下图中显示的信息:
从堆栈跟踪信息中,你可以看到它指向我们使用throw关键字的那一行,后面跟着调用SetVolume方法的那一行。这些信息在调试时非常有用。
重新抛出异常
上一节中的异常会沿着调用堆栈向上传播,由于我们没有代码来捕获和处理异常,因此程序崩溃了。捕获到异常后,我们可以执行一些操作,例如记录错误,然后重新抛出异常。重新抛出异常意味着在 catch 块内调用不带异常对象的throw语句。它只能在 catch 块内使用。
让我们创建一个新的控制台应用程序并使用以下内容更新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());
Console.WriteLine(calculator.Divide(number, divisor));
}
class Calculator
{
public int Divide(int number, int divisor)
{
try
{
return number / divisor;
}
catch (DivideByZeroException)
{
//TODO: log error
Console.WriteLine("Can't divide by 0");
throw;//propage this error
}
}
}
}
}
从上面的代码中,我们有一个带有Divide方法的计算器类。在 .NET 中,当一个数字被 0 除时,它会抛出 DivideByZeroException 。在Divide方法中,我们有代码来捕获此异常,记录到控制台,并重新抛出异常。运行应用程序并输入除数 0:
您可以看到,当我们将 0 作为除数传递给它时,它会在重新抛出异常之前将 Can't divided by 0打印到控制台。请注意,堆栈跟踪仍然保留了正确的信息,指向第 26 行作为发生错误的行,即使它是在第 32 行重新抛出的。人们在打算重新抛出异常时常犯的一个错误是使用捕获的异常对象调用throw关键字。以下是一个例子:
catch (DivideByZeroException ex)
{
//TODO: log error
Console.WriteLine("Can't divide by 0");
throw ex;//propage this error
}
如果我们以这种方式实现它,它将打印出以下堆栈跟踪:
Unhandled Exception: System.DivideByZeroException: Attempted to divide by zero.
at MyApp.Program.Calculator.Divide(Int32 number, Int32 divisor) in /Users/pmbanugo/Documents/projects/dotnet/MyApp/Program.cs:line 32
at MyApp.Program.Main(String[] args) in /Users/pmbanugo/Documents/projects/dotnet/MyApp/Program.cs:line 17
您可以看到它指向第 32 行,即抛出异常的行,而不是发生异常的行。重新抛出异常只需调用 throw 而不使用异常对象即可。
就此结束
有时我们的应用程序出现错误是因为代码错误,有时则是因为应用程序代码中未考虑到的错误用户输入。当正在运行的应用程序遇到错误时,会引发异常。在本指南中,我们研究了如何使用throw关键字来引发和重新引发异常,并解释了重新引发异常的正确语法。
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~