服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - 浅谈C#中简单的异常引发与处理操作

浅谈C#中简单的异常引发与处理操作

2021-11-11 14:26C#教程网 C#

这篇文章主要介绍了C#中简单的异常引发与处理操作,讲到了Exception类和try...catch及throw语句的基本使用,需要的朋友可以参考下

异常和异常处理
C# 语言的异常处理功能可帮助您处理程序运行时出现的任何意外或异常情况。异常处理使用 try、catch 和 finally 关键字尝试某些操作,以处理失败情况,尽管这些操作有可能失败,但如果您确定需要这样做,且希望在事后清理资源,就可以尝试这样做。公共语言运行时 (CLR)、.NET Framework 或任何第三方库或者应用程序代码都可以生成异常。异常是使用 throw 关键字创建的。
很多情况下,异常可能不是由代码直接调用的方法引发,而是由调用堆栈中位置更靠下的另一个方法所引发。在这种情况下,CLR 将展开堆栈,查找是否有方法包含针对该特定异常类型的 catch 块,如果找到这样的方法,就会执行找到的第一个这样的 catch 块。如果在调用堆栈中的任何位置都没有找到适当的 catch 块,就会终止该进程,并向用户显示一条消息。
此示例中使用一个方法检测是否有被零除的情况;如果有,则捕获该错误。如果没有异常处理,此程序将终止并产生“DivideByZeroException 未处理”错误。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class ExceptionTest
{
  static double SafeDivision(double x, double y)
  {
    if (y == 0)
      throw new System.DivideByZeroException();
    return x / y;
  }
  static void Main()
  {
    // Input for test purposes. Change the values to see
    // exception handling behavior.
    double a = 98, b = 0;
    double result = 0;
 
    try
    {
      result = SafeDivision(a, b);
      Console.WriteLine("{0} divided by {1} = {2}", a, b, result);
    }
    catch (DivideByZeroException e)
    {
      Console.WriteLine("Attempted divide by zero.");
    }
  }
}

异常概述
异常具有以下特点:

  • 各种类型的异常最终都是由 System.Exception 派生而来。
  • 在可能引发异常的语句周围使用 try 块。
  • 一旦 try 块中发生异常,控制流将跳转到第一个关联的异常处理程序(无论该处理程序存在于调用堆栈中的什么位置)。在 C# 中,catch 关键字用于定义异常处理程序。
  • 如果给定异常没有异常处理程序,则程序将停止执行,并显示一条错误消息。
  • 除非您可以处理某个异常并使应用程序处于已知状态,否则请不要捕捉该异常。如果捕捉 System.Exception,请在 catch 块的末尾使用 throw 关键字再次引发该异常。
  • 如果 catch 块定义了一个异常变量,则可以用它获取有关所发生异常类型的更多信息。
  • 程序可以使用 throw 关键字显式地引发异常。
  • 异常对象包含有关错误的详细信息,比如调用堆栈的状态以及有关错误的文本说明。
  • 即使发生异常也会执行 finally 块中的代码。使用 finally 块释放资源,例如,关闭在 try 块中打开的任何流或文件。

使用异常
在 C# 中,程序中的运行时错误通过使用一种称为“异常”的机制在程序中传播。 异常由遇到错误的代码引发,由能够更正错误的代码捕捉。 异常可由 .NET Framework 公共语言运行时 (CLR) 或由程序中的代码引发。 一旦引发了一个异常,这个异常就会在调用堆栈中往上传播,直到找到针对它的 catch 语句。 未捕获的异常由系统提供的通用异常处理程序处理,该处理程序会显示一个对话框。
异常由从 Exception 派生的类表示。 此类标识异常的类型,并包含详细描述异常的属性。 引发异常涉及到创建一个异常派生类的实例,配置异常的属性(可选),然后使用 throw 关键字引发该对象。 例如:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class CustomException : Exception
{
  public CustomException(string message)
  {
 
  }
 
}
private static void TestThrow()
{
  CustomException ex =
    new CustomException("Custom exception in TestThrow()");
 
  throw ex;
}

 


在引发异常之后,运行时检查当前语句以确定它是否在 try 块中。 如果是,则检查与该 try 块关联的任何 catch 块,以确定它们是否能够捕获该异常。 Catch 块通常会指定异常类型;如果该 catch 块的类型与异常或异常的基类的类型相同,则该 catch 块就能够处理该方法。 例如:

?
1
2
3
4
5
6
7
8
9
10
11
static void TestCatch()
{
  try
  {
    TestThrow();
  }
  catch (CustomException ex)
  {
    System.Console.WriteLine(ex.ToString());
  }
}


如果引发异常的语句不在 try 块中,或者包含该语句的 try 块没有匹配的 catch 块,运行时将检查调用方法中是否有 try 语句和 catch 块。 运行时将在调用堆栈中向上继续搜索兼容的 catch 块。 在找到并执行 catch 块之后,控制权将传递给 catch 块之后的下一个语句。
一个 try 语句可能包含多个 catch 块。 将执行第一个能够处理该异常的 catch 语句;任何后续的 catch 语句都将被忽略,即使它们是兼容的也如此。 因此,在任何情况下都应该按照从最具体(或者派生程度最高)到最不具体这一顺序排列 catch 块。 例如:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
static void TestCatch2()
{
  System.IO.StreamWriter sw = null;
  try
  {
    sw = new System.IO.StreamWriter(@"C:\test\test.txt");
    sw.WriteLine("Hello");
  }
 
  catch (System.IO.FileNotFoundException ex)
  {
    // Put the more specific exception first.
    System.Console.WriteLine(ex.ToString());
  }
 
  catch (System.IO.IOException ex)
  {
    // Put the less specific exception last.
    System.Console.WriteLine(ex.ToString());
  }
  finally
  {
    sw.Close();
  }
 
  System.Console.WriteLine("Done");
}


执行 catch 块之前,运行时会检查 finally 块。 Finally 块使程序员能够清除中止的 try 块可能遗留下的任何模糊状态,或者释放任何外部资源(例如图形句柄、数据库连接或文件流),而无需等待运行时中的垃圾回收器终结这些对象。 例如:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
static void TestFinally()
{
  System.IO.FileStream file = null;
  //Change the path to something that works on your machine.
  System.IO.FileInfo fileInfo = new System.IO.FileInfo(@"C:\file.txt");
 
  try
  {
    file = fileInfo.OpenWrite();
    file.WriteByte(0xF);
  }
  finally
  {
    // Closing the file allows you to reopen it immediately - otherwise IOException is thrown.
    if (file != null)
    {
      file.Close();
    }
  }
 
  try
  {
    file = fileInfo.OpenWrite();
    System.Console.WriteLine("OpenWrite() succeeded");
  }
  catch (System.IO.IOException)
  {
    System.Console.WriteLine("OpenWrite() failed");
  }
}

 


如果 WriteByte() 引发了异常,那么在没有调用 file.Close() 的情况下,第二个 try 块中尝试重新打开文件的代码就会失败,并且文件将保持锁定状态。 由于要执行 finally 块(即使已引发异常),前一示例中的 finally 块使得可以正确地关闭文件,从而帮助避免错误。
如果在引发异常之后没有在调用堆栈上找到兼容的 catch 块,则会出现三种情况中的一种:
如果异常出现在析构函数中,则中止该析构函数并调用基析构函数(如果有)。
如果调用堆栈包含静态构造函数或静态字段初始值设定项,则引发一个 TypeInitializationException,并将原始异常分配给新异常的 InnerException 属性。
如果到达线程的开头,则终止线程。

延伸 · 阅读

精彩推荐
  • C#深入理解C#的数组

    深入理解C#的数组

    本篇文章主要介绍了C#的数组,数组是一种数据结构,详细的介绍了数组的声明和访问等,有兴趣的可以了解一下。...

    佳园9492021-12-10
  • C#C#设计模式之Strategy策略模式解决007大破密码危机问题示例

    C#设计模式之Strategy策略模式解决007大破密码危机问题示例

    这篇文章主要介绍了C#设计模式之Strategy策略模式解决007大破密码危机问题,简单描述了策略模式的定义并结合加密解密算法实例分析了C#策略模式的具体使用...

    GhostRider10972022-01-21
  • C#SQLite在C#中的安装与操作技巧

    SQLite在C#中的安装与操作技巧

    SQLite,是一款轻型的数据库,用于本地的数据储存。其优点有很多,下面通过本文给大家介绍SQLite在C#中的安装与操作技巧,感兴趣的的朋友参考下吧...

    蓝曈魅11162022-01-20
  • C#如何使用C#将Tensorflow训练的.pb文件用在生产环境详解

    如何使用C#将Tensorflow训练的.pb文件用在生产环境详解

    这篇文章主要给大家介绍了关于如何使用C#将Tensorflow训练的.pb文件用在生产环境的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴...

    bbird201811792022-03-05
  • C#C#微信公众号与订阅号接口开发示例代码

    C#微信公众号与订阅号接口开发示例代码

    这篇文章主要介绍了C#微信公众号与订阅号接口开发示例代码,结合实例形式简单分析了C#针对微信接口的调用与处理技巧,需要的朋友可以参考下...

    smartsmile20127762021-11-25
  • C#VS2012 程序打包部署图文详解

    VS2012 程序打包部署图文详解

    VS2012虽然没有集成打包工具,但它为我们提供了下载的端口,需要我们手动安装一个插件InstallShield。网上有很多第三方的打包工具,但为什么偏要使用微软...

    张信秀7712021-12-15
  • C#利用C#实现网络爬虫

    利用C#实现网络爬虫

    这篇文章主要介绍了利用C#实现网络爬虫,完整的介绍了C#实现网络爬虫详细过程,感兴趣的小伙伴们可以参考一下...

    C#教程网11852021-11-16
  • C#三十分钟快速掌握C# 6.0知识点

    三十分钟快速掌握C# 6.0知识点

    这篇文章主要介绍了C# 6.0的相关知识点,文中介绍的非常详细,通过这篇文字可以让大家在三十分钟内快速的掌握C# 6.0,需要的朋友可以参考借鉴,下面来...

    雨夜潇湘8272021-12-28