简单的讲一些不涉及到线程问题的异常处理,包括下面几个部分,
异常和异常类的介绍
try catch finally thorw关键字
try的嵌套
catch块的顺序
自定义异常类
再高明的程序因为种种可控制或者不可控制的原因在代码中都会产生异常,比如说遇到除数为0,打开一个不存在的文件,网络断开,等等不可预料的异常。这个就需要使用到异常处理机制。
在发生任何异常时程序都会抛出一个Exception类的子类对象,当中包含异常的信息。
这张图给出C#设计中部分已经定义好的类的继承关系。
其中SystemException是运行时异常,ApplicationException用于第三方自定义类,如果我们希望定义一个自定义类就可以继承这个类
下面再给出一张表格列举出一些常见的异常类
异常类名称 简单描述
MemberAccessException 访问错误:类型成员不能被访问 ArgumentException 参数错误:方法的参数无效 ArgumentNullException 参数为空:给方法传递一个不可接受的空参数 ArithmeticException 数学计算错误:由于数学运算导致的异常,覆盖面广。 ArrayTypeMismatchException 数组类型不匹配 DivideByZeroException 被零除 FormatException 参数的格式不正确 IndexOutOfRangeException 索引超出范围,小于0或比最后一个元素的索引还大 InvalidCastException 非法强制转换,在显式转换失败时引发 MulticastNotSupportedException 不支持的组播:组合两个非空委派失败时引发 NotSupportedException 调用的方法在类中没有实现 NullReferenceException 引用空引用对象时引发 OutOfMemoryException 无法为新语句分配内存时引发,内存不足 OverflowException 溢出 StackOverflowException 栈溢出 TypeInitializationException 错误的初始化类型:静态构造函数有问题时引发 NotFiniteNumberException 无限大的值:数字不合法
写了这么多还没说怎么设计使用异常基本的格式是
try { //.............. } catch { //............... } finally { //............... } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }try块部分写可能抛出异常的代码
catch块写出现异常后针对的处理办法
finally写不论是否出现异常都执行的代码(通常是一些释放资源的代码),finally块是可以省略的。
具体的看一段代码
1: static void Main(string[] args) 2: { 3: int n1 = 10; 4: int n2 = 0; 5: int result; 6: try 7: { 8: result = n1 / n2; 9: Console.WriteLine("{0}", result); 10: } 11: catch (DivideByZeroException e) 12: { 13: Console.WriteLine(e.Message); 14: } 15: catch (Exception e) 16: { 17: Console.WriteLine(e.Message); 18: } 19: finally 20: { 21: Console.WriteLine("finally"); 22: } 23: Console.ReadKey(); 24: } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }输出结果为
一个try块可以对应多个catch块,其中按抛出的异常类寻找对应的catch块,也可能找不到,如果一直没有找到就会终止程序,返回一条错误代码。
但是要注意的每个catch块之间是有顺序的,子类必须写在父类之前,不然无法编译过。
而且异常处理可以互相嵌套,在内层找不到对应的处理代码,会向外层找。
而且具MSDN的说法“很多情况下,异常可能不是由代码直接调用的方法引发,而是由调用堆栈中位置更靠下的另一个方法所引发。 在这种情况下,CLR 将展开堆栈,查找是否有方法包含针对该特定异常类型的 catch 块,如果找到这样的方法,就会执行找到的第一个这样的 catch 块。 如果在调用堆栈中的任何位置都没有找到适当的 catch 块,就会终止该进程,并向用户显示一条消息。”
具体看下面的代码
1: static void Main(string[] args) 2: { 3: int n1 = 10; 4: int n2 = 0; 5: int result; 6: try 7: { 8: try 9: { 10: result = n1 / n2; 11: Console.WriteLine("{0}", result); 12: } 13: catch (MemberAccessException e) 14: { 15: Console.WriteLine(e.Message); 16: } 17: finally 18: { 19: Console.WriteLine("finally1"); 20: } 21: } 22: catch (Exception e) 23: { 24: Console.WriteLine(e.Message); 25: } 26: finally 27: { 28: Console.WriteLine("finally2"); 29: } 30: Console.ReadKey(); 31: } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }输出结果
最后讲一下我们可以用throw语句手工抛出一个异常类,和如何自定义异常类。
下面代码,实现了double除法时除数的检测,除数为0时抛出一个异常。C#对double除以0的情况会返回一个无穷大量,而不是异常。
具体可以查看double定义中的PositiveInfinity和IsPositiveInfinity.
1: private class TestException : ApplicationException 2: { 3: public string msg; 4: public TestException(string msg) 5: { 6: this.msg = msg; 7: } 8: } 9: static double mul(double n1, double n2) 10: { 11: if (n2 == 0.0) 12: { 13: throw new TestException("除数为0"); 14: } 15: 16: return n1 / n2; 17: } 18: static void Main(string[] args) 19: { 20: double n1 = 10.0; 21: double n2 = 0.0; 22: double result; 23: try 24: { 25: result = mul(n1, n2); 26: Console.WriteLine(result); 27: } 28: catch (TestException e) 29: { 30: Console.WriteLine(e.msg); 31: } 32: Console.ReadKey(); 33: } 34: 35: }.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
输出结果
除数为0
相关文章
http://www.microsoft.com/China/Community/program/originalarticles/TechDoc/errorhandling.mspx
http://www.legalsoft.com.cn/docs/573.html
http://msdn.microsoft.com/zh-cn/library/system.exception.aspx?appId=Dev10IDEF1&l=ZH-CN&k=k(EHINVALIDOPERATION);k(TargetFrameworkMoniker-
http://msdn.microsoft.com/zh-cn/library/ms173160.aspx
http://msdn.microsoft.com/zh-cn/library/ms173162.aspx
http://msdn.microsoft.com/zh-cn/library/ms173163.aspx