• [C#] C# 知识回顾


    学会使用异常

      异常:指的是我们写的程序在运行时出现了错误,并且它会不断的蔓延、传播和扩散,有点像病毒一样。

      异常通常由错误的代码引发,可能是用户的错误输入,可能是一方没有按照约定来传输格式,也可能是数据传输的过程中被篡改。我们会对自己认为有可能报错的代码进行 catch ,这称为捕获异常。

      一旦引发了异常,这个异常将会在调用堆栈中一直向上进行传播,直到寻找到跟它匹配的 catch 语句。没有 catch 的异常会由系统提供的默认的异常处理程序进行处理,也就是你经常看到的一个突然造成调试中断并显示异常信息的对话框。

      所有的异常,它都是从 Exception 派生出来的,他们都包含了详细的异常描述属性。在这里我将自定义了一个新的异常类,然后使用 throw 关键字显式引发该对象(即异常)。 

     1         /// <summary>
     2         /// 定义新异常
     3         /// </summary>
     4         class MyException : Exception
     5         {
     6             public MyException(string msg) { }
     7         }
     8 
     9         /// <summary>
    10         /// 抛出新定义的异常
    11         /// </summary>
    12         static void ThrowMyExcetion()
    13         {
    14             throw new MyException("Sorry, this is test!");
    15         }

      

      在引发异常之后,CLR 运行时程序会检查当前语句确定它是否包含在 try 块中。 如果是的话,就会检查与该 try 块相关联的所有 catch 块,来确定它们是否能够 catch 该异常。如果该 catch 块的类型与异常或它的基类的相同(或匹配),则该 catch 块就能够捕获并处理。

     1         static void Main(string[] args)
     2         {
     3             try
     4             {
     5                 ThrowMyExcetion();  //直接调用抛出异常的方法
     6             }
     7             catch (MyException e)
     8             {
     9                 Console.WriteLine(e);
    10             }
    11 
    12             Console.Read();
    13         }

      如果引发异常的语句不在 try 块中,或者包含该语句的 try 块没有匹配的 catch 块,CLR 运行时将检查调用方法中是否有合适 try 语句和 catch 块。 运行时将在调用堆栈中继续往上搜索兼容(或匹配)的 catch 块。在找到并执行 catch 块之后,控制权将传递给 catch 块之后的下一个语句。

      一个 try 语句可能包含多个 catch 块。 将执行第一个能够处理该异常的 catch 语句;任何后续的 catch 语句都将被忽略。 因此,在任何情况下都应该按照从最具体(或者派生程度最高)到最不具体这一顺序排列 catch 块。 例如:

     1         static void Main(string[] args)
     2         {
     3             StreamWriter sw = null;
     4 
     5             try
     6             {
     7                 sw = new StreamWriter(@"C:ook小二和小三的故事.txt");
     8                 sw.Write("You are 250.");
     9             }
    10             catch (FileNotFoundException e)
    11             {
    12                 //将具体的异常放在第一位
    13                 Console.WriteLine(e);
    14             }
    15             catch (IOException e)
    16             {
    17                 //将并不具体的放在相对后面的位置
    18                 Console.WriteLine(e);
    19             }
    20             catch (Exception e)
    21             {
    22                 Console.WriteLine(e);
    23             }
    24             finally
    25             {
    26                 if (sw != null)
    27                 {
    28                     sw.Close();
    29                 }
    30             }
    31 
    32             Console.Read();
    33         }

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

     1         static void Main(string[] args)
     2         {
     3             FileStream fs = null;
     4             FileInfo fi = new FileInfo(@"小二和小三的故事.txt");
     5 
     6             try
     7             {
     8                 fs = fi.OpenWrite();
     9                 fs.WriteByte(0);
    10             }
    11             finally
    12             {
    13                 //记住哦,如果你忘记 close,将会引发 IO 异常!
    14                 //if (fs != null)
    15                 //{
    16                 //    fs.Close();
    17                 //}
    18             }
    19 
    20             try
    21             {
    22                 fs = fi.OpenWrite();
    23                 fs.WriteByte(1);
    24                 Console.WriteLine("OK!");
    25             }
    26             catch (IOException e)
    27             {
    28                 Console.WriteLine("Fail!");
    29             }
    30 
    31             Console.Read();
    32         }

      “Fail!”,这是因为上面注释了需要关闭文件流的语句,你可以尝试下去掉注释看看结果,记住哦,IO 操作都应该在结束时释放资源。 

      如果 WriteByte(0)(第9行) 引发了异常,那么在没有调用 fs.Close() 的情况下,你在第二个 try 块中尝试重新 OpenWrit() 的代码就会失败,因为此时文件会保持锁定状态。 假如你取消注释,由于会执行 finally 块(即使已引发异常),使得可以正确地关闭文件,从而避免再次引发异常。

      如果在引发异常之后没有在调用堆栈上找到相匹配的 catch 块,则:

    • 如果异常出现在析构函数中,则中止该析构函数并调用基类的析构函数(如果有)。

    • 如果调用堆栈包含静态构造函数或静态字段初始值设定项,则会引发 TypeInitializationException,并将原始异常分配给新异常的 InnerException 属性。

    • 如果到达线程的开头,将会终止线程。

    C# 基础回顾系列 

      《C# 知识回顾 - 委托 delegate》、《C# 知识回顾 - 委托 delegate (续)

      《C# 知识回顾 - 事件入门》、《C# 知识回顾 - Event 事件

      《string 与 String,大 S 与小 S 之间没有什么不可言说的秘密

      《C# 知识回顾 - 异常介绍


    【博主】反骨仔

    【出处】http://www.cnblogs.com/liqingwen/p/6193534.html

    【参考】https://docs.microsoft.com/zh-cn/dotnet/articles/csharp/programming-guide/exceptions/using-exceptions

    【参考】微软官方文档

  • 相关阅读:
    收集起来先
    asp .net 页面回车触发button 按钮事件
    关于SQL 数据库表中的聚集索引和非聚集索引等
    WinForm换肤操作(用IrisSkin2.dll)
    生成Word文档的相关操作
    API自动化测试测试数据集
    API文档实践
    使用eolinker对API测试的响应结果进行断言
    API自动化定时测试
    接口测试之对数据进行RSA加解密
  • 原文地址:https://www.cnblogs.com/liqingwen/p/6193534.html
Copyright © 2020-2023  润新知