C# 异常
最后修改于 2023 年 7 月 5 日
本文介绍了如何在 C# 中处理异常。
异常表示应用程序执行期间发生的错误。
在应用程序执行期间,可能会发生很多错误。磁盘可能已满,我们无法保存文件。当我们的应用程序尝试连接到某个站点时,Internet 连接可能会中断。这些错误可能会导致问题,包括应用程序崩溃。程序员有责任处理可以预测的错误。
try
、catch
和 finally
关键字用于处理异常。
Exception
是所有异常的基类。错误通过抛出异常来报告。抛出异常后,它由应用程序或默认异常处理程序处理。该异常包含有关错误的信息。
在应用程序开发期间和开发完成后,会抛出不同类型的异常。开发人员会收到包含大量技术细节的异常,而用户只会收到简短的基本信息消息。
C# 捕获异常
catch
关键字用于捕获抛出的异常。
int x = 100; int y = 0; int z; try { z = x / y; } catch (ArithmeticException e) { Console.WriteLine("An exception occurred"); Console.WriteLine(e.Message); }
在上面的程序中,我们故意将一个数字除以零。这会导致错误。请注意,这是一个学术示例,用于演示异常如何工作。实际上,除以错误是一个程序错误,可以通过确保分母不为零来解决。
try { z = x / y; }
容易出错的语句放在 try
块中。
catch (ArithmeticException e) { Console.WriteLine("An exception occurred"); Console.WriteLine(e.Message); }
异常类型跟在 catch
关键字之后。在我们的例子中,我们有一个 ArithmeticException
。为算术、强制转换或转换操作中的错误抛出此异常。当发生错误时,执行跟在 catch
关键字之后的语句。当发生异常时,会创建一个异常对象。我们从该对象中获取 Message
属性并将其打印到控制台。
$ dotnet run An exception occurred Attempted to divide by zero.
C# 未捕获的异常
当前上下文中任何未捕获的异常都会传播到更高的上下文,并查找适当的 catch 块来处理它。如果找不到任何合适的 catch 块,.NET 运行时的默认机制将终止整个程序的执行。
int x = 100; int y = 0; int z = x / y; Console.WriteLine(z);
在此程序中,我们将除以零。没有自定义异常处理。
$ dotnet run Unhandled exception. System.DivideByZeroException: Attempted to divide by zero. ...
C# 编译器给出了上述错误消息。
C# IOException
当发生 I/O 错误时,会抛出 IOException
。在下面的示例中,我们读取文件的内容。
var fs = new FileStream("langs.txt", FileMode.OpenOrCreate); try { var sr = new StreamReader(fs); string? line; while ((line = sr.ReadLine()) != null) { Console.WriteLine(line); } } catch (IOException e) { Console.WriteLine("IO Error"); Console.WriteLine(e.Message); } finally { Console.WriteLine("Inside finally block"); if (fs != null) { fs.Close(); } }
finally
关键字后面的语句始终执行。它通常用于清理任务,例如关闭文件或清除缓冲区。
catch (IOException e) { Console.WriteLine("IO Error"); Console.WriteLine(e.Message); }
在这种情况下,我们捕获特定的 IOException
异常。
finally { Console.WriteLine("Inside finally block"); if (fs != null) { fs.Close(); } }
这些行保证文件句柄已关闭。
$ cat langs.txt C# Java Python Ruby PHP JavaScript
这些是 langs.txt
文件的内容。
$ dotnet run C# Java Python Ruby PHP JavaScript Inside finally block
C# 多个异常
我们经常需要处理多个异常。
int x; int y; double z; try { Console.Write("Enter first number: "); x = Convert.ToInt32(Console.ReadLine()); Console.Write("Enter second number: "); y = Convert.ToInt32(Console.ReadLine()); z = x / y; Console.WriteLine("Result: {0:N} / {1:N} = {2:N}", x, y, z); } catch (DivideByZeroException e) { Console.WriteLine("Cannot divide by zero"); Console.WriteLine(e.Message); } catch (FormatException e) { Console.WriteLine("Wrong format of number."); Console.WriteLine(e.Message); }
在此示例中,我们捕获各种异常。请注意,更具体的异常应位于通用异常之前。我们从控制台读取两个数字,并检查零除错误和错误的数字格式。
$ dotnet run Enter first number: we Wrong format of number. Input string was not in a correct format.
C# 自定义异常
自定义异常是用户定义的异常类,它派生自 System.Exception
类。
int x = 340004; const int LIMIT = 333; try { if (x > LIMIT) { throw new BigValueException("Exceeded the maximum value"); } } catch (BigValueException e) { Console.WriteLine(e.Message); } class BigValueException : Exception { public BigValueException(string msg) : base(msg) { } }
我们假设我们遇到无法处理大数字的情况。
class BigValueException : Exception
我们有一个 BigValueException
类。该类派生自内置的 Exception
类。
const int LIMIT = 333;
大于此常量的数字被我们的程序认为是“大”数字。
public BigValueException(string msg) : base(msg) {}
在构造函数内部,我们调用父类的构造函数。我们将消息传递给父类。
if (x > LIMIT) { throw new BigValueException("Exceeded the maximum value"); }
如果该值大于限制,我们将抛出我们的自定义异常。我们给异常一个消息“超过最大值”。
catch (BigValueException e) { Console.WriteLine(e.Message); }
我们捕获异常并将其消息打印到控制台。
$ dotnet run Exceeded the maximum value
来源
本文介绍了如何在 C# 中处理异常。
作者
列出所有 C# 教程。