什么是异常?
异常是程序执行时遇到的任何错误情况或意外行为。以下这些情况都可以引发异常:您的代码或调用的代码(如共享库)中有错误,操作系统资源不可用,公共语言运行库遇到意外情况(如无法验证代码),等等。对于这些情况,应用程序可以从其中一些恢复,而对于另一些,则不能恢复。尽管可以从大多数应用程序异常中恢复,但不能从大多数运行库异常中恢复。由于ASP.NET是在网络环境中运行的,安全成为需要首先考虑的重要因素之一。为了能够及时有效地处理程序中的运行错误,引入了异常和异常类。作为面向对象的语言,异常与其他语言要素一样,是面向对象规范的一部分,是异常类的对象。
异常类和属性
Exception 类是异常从其进行继承的基类。大多数异常对象都是 Exception 的某个派生类的实例,不过,任何从 Object 类派生的对象都可以作为异常引发。
Exception 类的若干属性使了解异常更容易。这些属性包括:
1、StackTrace 属性。
此属性包含可用来确定错误发生位置的堆栈跟踪。如果有可用的调试信息,则堆栈跟踪包含源文件名和程序行号。
2、InnerException 属性。
此属性可用来在异常处理过程中创建和保留一系列异常。可使用此属性创建一个新异常来包含以前捕捉的异常。原始异常可由 InnerException 属性中的第二个异常捕获,这使处理第二个异常的代码可以检查附加信息。
例如,假设有一个读取文件并格式化相应数据的方法。代码试图从文件读取,但引发 FileException。该方法捕捉 FileException 并引发 BadFormatException。在此情况下,FileException 可保存在 BadFormatException 的 InnerException 属性中。
为提高调用方确定异常引发原因的能力,有时可能需要方法捕捉帮助器例程引发的异常,然后引发一个进一步指示已发生的错误的异常。可以创建一个更有意义的新异常,其中内部异常引用可以设置为原始异常。然后可以针对调用方引发这种更有意义的异常。请注意,使用此功能,可以创建以最先引发的异常作为结束点的一系列相链接的异常。
3、Message 属性。
此属性提供有关异常起因的详细信息。Message 用引发异常的线程的 Thread.CurrentUICulture 属性所指定的语言表示。
4、HelpLink 属性。
此属性可保存某个帮助文件的 URL(或 URN),该文件提供有关异常起因的大量信息。
5、Data 属性
此属性是可以保存任意数据(以键值对的形式)的 IDictionary。
大多数从 Exception 继承的类都不实现其他成员或提供附加功能;它们只是从 Exception 继承。因此,在异常层次结构、异常名称以及异常包含的信息中可以找到有关异常的最重要信息。
c#异常处理所用到的几个关键字:
1、try 用于检查发生的异常,并帮助发送任何可能的异常。
2、catch 以控制权更大的方式处理错误,可以有多个catch子句。
3、finally 无论是否引发了异常,finally的代码块都将被执行。
4、throw 用于引发异常,可引发预定义异常和自定义异常。
{
程序代码块;
}
catch(Exception e)
{
异常处理代码块;
}
finally
{
无论是否发生异常,均要执行的代码块;
}
下面看一个简单的例子:
int y = 0;
try
{
int z = x / y;
}
catch (DivideByZeroException ex)
{
Response.Write("除数不能为0,你知道吗?" + ex.Message);
}
finally
{
Response.Write("无论是否有异常,我都会出现");
}
运行的输出结果是:
2、每个try语句必须有一个或多个catch语句对应,try代码块与catch代码块以及finally代码块之间不能有其他语句。下面的语句是错误的:
}
catch (DivideByZeroException ex)
{
......
}
x = 8;//放在这里是不行滴
finally
{
.....
}
可以给try语句提供多个catch语句,以捕获特定的异常,如上例中:0作为除数则会引发DivideByZeroException类型的异常,上例中的catch语句可以作如下修改:
{
Response.Write("零不能作为除数!异常值为:" + e.message);
}
catch(Exception e)
{
Response.Write("零作为除数引发的异常/"!异常值为:" + e.message);
}
为什么还要加上一个catch(Exception e)子句呢?原因很简单,catch(DivideByZeroException e)子句只能捕获特定的异常,try内的程序代码可能还会产生其它的异常,这些异常只能由catch(Exception e)来捕获了。
ArgumentException 参数错误:方法的参数无效
ArgumentNullException 参数为空:给方法传递一个不可接受的空参数
ArithmeticException 数学计算错误:由于数学运算导致的异常,覆盖面广。
ArrayTypeMismatchException 数组类型不匹配
DivideByZeroException 被零除
FormatException 参数的格式不正确
IndexOutOfRangeException 索引超出范围,小于0或比最后一个元素的索引还大
InvalidCastException 非法强制转换,在显式转换失败时引发
MulticastNotSupportedException 不支持的组播:组合两个非空委派失败时引发
NotSupportedException 调用的方法在类中没有实现
NullReferenceException 引用空引用对象时引发
OutOfMemoryException 无法为新语句分配内存时引发,内存不足
OverflowException 溢出
StackOverflowException 栈溢出
TypeInitializationException 错误的初始化类型:静态构造函数有问题时引发
NotFiniteNumberException 无限大的值:数字不合法
除了系统提供的异常,我们也可以定义自己的异常类,该类必须继承于Exception,下面举个简单例子:
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.IO;
public partial class Default2 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
int num = 1;
try
{
if (num > 0)
{
throw new myException();
}
}
catch (myException ex1)
{
Response.Write(ex1.Message);
}
catch (Exception ex2)
{
Response.Write("如果第一个catch过了,还得过我这一关,出现的错误原因是:" + ex2.Message);
}
finally
{
Response.Write("");
}
}
//重写Exception的Message
protected class myException:Exception
{
public override string Message
{
get
{
return "大于0,你不知道吗?";
}
}
}
}
上面的例子重写了Execpton中的Message属性。
1、一个方法被覆盖时,覆盖它的方法必须抛出相同的异常或异常的子类。
2、如果父类抛出多个异常,那么重写(覆盖)方法必须抛出那些异常的一个子集,也就是说,不能抛出新的异常。
以前语言要求程序员使用函数调用的返回值来判断执行情况,这种方式有很多缺陷,因为对许多可能出现的异常情况需要不同程度的了解。有些语言使用一个全局变量来保存异常状态,但这种方式是远远不够的,因为后面的异常会在前一个异常还未处理之前就覆盖了那个全局变量的值。