2024年3月21日发(作者:)

Exception

此类是所有异常的基类。当发生错误时,系统或当前正在执行的

应用程序通过引发包含关于该错误的信息的异常来报告错误。异常发

生后,将由该应用程序或默认异常处理程序进行处理。

Exception 类是异常从其进行继承的基类。大多数异常对象都是

Exception 的某个派生类的实例,不过,任何从 Object 类派生的对

象都可以作为异常引发。请注意,并非所有语言都支持引发和捕捉不

从 Exception 派生的对象。在几乎任何情况下,都建议仅引发和捕捉

Exception 对象。

公共语言运行库提供一种异常处理模型,该模型基于对象形式的异常

表示形式,并且将程序代码和异常处理代码分到 try 块和 catch 块

中。可以有一个或多个 catch 块,每个块都设计为处理一种特定类型

的异常,或者将一个块设计为捕捉比其他块更具体的异常。

如果应用程序将处理在执行应用程序代码块期间发生的异常,则

代码必须放置在 try 语句中。try 语句中的应用程序代码是 try 块。

处理由 try 块引发的异常的应用程序代码放在 catch 语句中,称为

catch 块。零个或多个 catch 块与一个 try 块相关联,每个 catch 块

均包含一个确定该块处理的异常类型的类型筛选器。

在 try 块中出现异常时,系统按所关联 catch 块在应用程序代码中

出现的顺序搜索它们,直到定位到处理该异常的 catch 块为止。如果

某 Catch 块的类型筛选器指定 T 或任何派生出 T 的类型,则该

catch 块处理 T 类型的异常。系统在找到第一个处理该异常的 catch

块后即停止搜索。因此,正如本节后面的示例所演示的那样,在应用

程序代码中处理某类型的 catch 块必须在处理其基类型的 catch 块

之前指定。处理 ion 的 Catch 块最后指定。

如果当前 try 块所关联的所有 catch 块均不处理该异常,且当前

try 块嵌套在当前调用的其他 try 块中,则搜索与下一个封闭 try 块

相关联的 catch 块。如果没有找到用于该异常的 catch 块,则系统

搜索当前调用中前面的嵌套级别。如果在当前调用中没有找到用于该

异常的 catch 块,则将该异常沿调用堆栈向上传递,搜索上一个堆栈

帧来查找处理该异常的 catch 块。继续搜索调用堆栈,直到该异常得

到处理或调用堆栈中没有更多的帧为止。如果到达调用堆栈顶部却没

有找到处理该异常的 catch 块,则由默认的异常处理程序处理该异

常,然后应用程序终止。

异常类型支持下面的功能:

描述错误的可读文本。当异常发生时,运行库产生文本消息通知

用户错误的性质并提供解决该问题的操作建议。此文本消息保存在异

常对象的 Message 属性中。在创建异常对象过程中,可以将文本字

符串传递给构造函数以描述该特定异常的详细信息。如果没有向构造

函数提供错误信息参数,则将使用默认错误信息。

发生异常时调用堆栈的状态。StackTrace 属性包含可以用来确定代码

中错误发生位置的堆栈跟踪。堆栈跟踪列出所有调用的方法和源文件

中这些调用所在的行号。

基类 Exception 下存在两类异常:

从 SystemException 派生的预定义公共语言运行库异常类。

从 ApplicationException 派生的用户定义的应用程序异常类。

Exception 包含很多属性,可以帮助标识异常的代码位置、类型、帮

助文件和原因:StackTrace、InnerException、Message、HelpLink、

HResult、Source、TargetSite 和 Data。

当在两个或多个异常之间存在因果关系时,InnerException 属性会维

护此信息。作为对此内部异常的反应将引发外部异常。处理外部异常

的代码可利用以前的内部异常的信息更妥当地处理错误。关于异常的

补充信息可以存储在 Data 属性中。

应本地化在创建异常对象过程中传递给构造函数的错误信息字符串,

这种字符串可以使用 ResourceManager 从资源文件提供。有关本地

化资源的更多信息,请参见“ces 命名空间概述”和“打包

和部署资源”。

若要向用户提供有关异常发生原因的大量信息,可以使用 HelpLink

属性保存帮助文件的 URL(或 URN)。

Exception 使用具有值 0x80131500 的 HRESULT

COR_E_EXCEPTION。

有关 Exception 实例的初始属性值列表,请参见 Exception 构造函

数。

性能注意事项

引发或处理异常时,将使用大量的系统资源和执行时间。引发异常只

是为了处理确实异常的情况,而不是为了处理可预知的事件或流控

制。例如,如果方法参数无效,而应用程序需要使用有效的参数调用

方法,则可以引发异常。无效的方法参数意味着出现了异常情况。相

反,用户偶尔会输入无效数据,这是可以预见的,因此如果用户输入

无效,则不要引发异常。在这种情况下,请提供重试机制以便用户输

入有效输入。

仅对特别条件引发异常,然后在应用于大多数应用程序的常规异常处

理程序中捕捉异常,而不是在应用于特定异常的处理程序中捕捉异

常。此方法的基础在于,大多数错误都可以通过验证以及与错误接近

的错误处理代码进行处理;不需要引发和捕捉异常。通用目的异常处

理程序捕捉的是在应用程序任意位置引发的、真正不可预期的异常。

此外,返回代码正常时不要引发异常;不要将返回代码转换为异

常;也不要例行公事地捕捉异常、忽略异常,然后继续处理。

using System;

class ExceptionTestClass

{

public static void Main()

{

int x = 0;

try

{

int y = 100/x;

}

catch (ArithmeticException e)

{

ine("ArithmeticException Handler: {0}", ng());

}

catch (Exception e)

{

ine("Generic Exception Handler: {0}", ng());

}

}

}

可以使用 Throw 语句显式引发异常。还可以使用 Throw 语句再

次引发捕捉的异常。好的编码做法是向再次引发的异常添加信息以在

调试时提供更多信息。

下面的代码示例使用 Try/Catch 块捕捉可能的

FileNotFoundException。Try 块后面是 Catch 块,Catch 块捕捉

FileNotFoundException,如果找不到数据文件,则向控制台写入消息。

下一条语句是 Throw 语句,该语句引发新的 FileNotFoundException

并向异常添加文本信息。

using System;

using ;

public class ProcessFile

{

public static void Main()

{

FileStream fs = null;

try

//Opens a text tile.

{

fs = new FileStream("", );

StreamReader sr = new StreamReader(fs);

string line;

//A value is read from the file and output to the console.

line = ne();

ine(line);

}

catch(FileNotFoundException e)

{

ine("[Data File Missing] {0}", e);

throw new FileNotFoundException("[ not in c:dev directory]",e);

}

finally

{

();

}

}

}

try-catch 语句由一个 try 块后跟一个或多个 catch 子句构成,这些

子句指定不同的异常处理程序。

try 块包含可能导致异常的保护代码。该块一直执行到引发异常或成

功完成为止。例如,下列强制转换 null 对象的尝试引发

NullReferenceException 异常:

object o2 = null;

try

{

int i2 = (int)o2; // Error

}

catch 子句使用时可以不带任何参数,这种情况下它捕获任何类型

的异常,并被称为一般 catch 子句。它还可以接受从

ion 派生的对象参数,这种情况下它处理特定的异常。

例如:

catch (InvalidCastException e)

{

}

在同一个 try-catch 语句中可以使用一个以上的特定 catch 子句。这

种情况下 catch 子句的顺序很重要,因为会按顺序检查 catch 子句。

将先捕获特定程度较高的异常,而不是特定程度较小的异常。

在 catch 块中可以使用 throw 语句再次引发已由 catch 语句捕获的

异常。例如:

catch (InvalidCastException e)

{

throw (e); // Rethrowing exception e

}

如果要再次引发当前由无参数的 catch 子句处理的异常,则使用不带

参数的 throw 语句。例如:

catch

{

throw;

}

在 try 块内部时应该只初始化其中声明的变量;否则,完成该块

的执行前可能发生异常。例如,在下面的代码示例中,变量 x 在 try

块内初始化。试图在 Write(x) 语句中的 try 块外部使用此变量时将

产生编译器错误:使用了未赋值的局部变量。

static void Main()

{

int x;

try

{

// Don't initialize this variable here.

x = 123;

}

catch

{

}

// Error: Use of unassigned local variable 'x'.

(x);

}