首页 > 代码库 > [C#] 学会使用异常(整理中)
[C#] 学会使用异常(整理中)
学会使用异常
在 C# 中,程序中的运行时错误通过使用一种称为“异常”的机制在程序中传播。 异常由错误的代码引发,并由能够更正错误的代码进行捕捉。 异常可由 .NET 的公共语言运行时 (CLR) 或由程序中的代码引发。 一旦引发了一个异常,这个异常就会在调用堆栈中向上传播,直到找到针对它的 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 }
在引发异常之后,运行时检查当前语句以确定它是否在 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
块,运行时将检查调用方法中是否有 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:\book\小二和小三的故事.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 finally25 {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 finally12 {13 //记住哦,如果你忘记 close,将会引发 IO 异常!14 //if (fs != null)15 //{16 // fs.Close();17 //}18 }19 20 try21 {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()
引发了异常,那么在没有调用 fs.Close()
的情况下,第二个 try
块中尝试重新打开文件的代码就会失败,并且文件将保持锁定状态。 由于要执行 finally
块(即使已引发异常),前一示例中的 finally
块使得可以正确地关闭文件,从而帮助避免错误。
如果在引发异常之后没有在调用堆栈上找到兼容的 catch
块,则会出现三种情况中的一种:
如果异常出现在析构函数中,则中止该析构函数并调用基析构函数(如果有)。
如果调用堆栈包含静态构造函数或静态字段初始值设定项,则引发一个 TypeInitializationException,并将原始异常分配给新异常的 InnerException 属性。
如果到达线程的开头,则终止线程。
【博主】反骨仔
【出处】http://www.cnblogs.com/liqingwen/p/6193534.html
【参考】微软官方文档
[C#] 学会使用异常(整理中)