c#自定义异常类

 
异常是一种的报告错误的机制,它可以在远离错误发生的地方进行处理错误。所有关于错误发生的的信息必须包含在异常对象中。在错误发生的过程中,你可能想把底层的错误转化成详细的应用程序错误,而且不丢失关于错误的任何信息。你须要仔细考虑关于如何在C#应用程序中创建特殊的异常类。第一步就是要理解什么时候以及为什么要创建新的异常类,以及如何构造继承的异常信息。当开发者使用你的库来写catch语句时,他们是基于特殊的进行时异常在区别为同的行为的。每一个不同的异常类可以有不同的处理要完成:OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
try {OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
Foo( );OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
Bar( );OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
} catch( MyFirstApplicationException e1 )b
{OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
FixProblem( e1 );OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
} catch( AnotherApplicationException e2 )OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
{OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
ReportErrorAndContinue( e2 );OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
} catch( YetAnotherApplicationException e3 )OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
{OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
ReportErrorAndShutdown( e3 );OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
} catch( Exception e )OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
{OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
ReportGenericError( e );OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
}OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
finallyOÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
{OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
CleanupResources( );OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
}OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
不同的catch语句可以因为不同的运行时异常而存在。你,做为库的作者,当异常的catch语句要处理不同的事情时,必须创建或者使用不同的异常类。如果不这样,你的用户就只有唯一一个无聊的选择。在任何一个异常抛出时,你可以挂起或者中止应用程序。这当然是最少的工作,但样是不可能从用户那里赢得声望的。或者,他们 可以取得异常,然后试着断定这个错误是否可以修正:OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
try {OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
Foo( );OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
Bar( );OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
} catch( Exception e )OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
{OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
switch( e.TargetSite.Name )OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
{OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
case "Foo":OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
FixProblem( e );OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
break;OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
case "Bar":OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
ReportErrorAndContinue( e );OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
break;OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
// some routine called by Foo or Bar:OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
default:OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
ReportErrorAndShutdown( e );OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
break;OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
}OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
} finallyOÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
{OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
CleanupResources( );OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
}OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
这远不及使用多个catch语句有吸引力,这是很脆弱的代码:如果只是常规的修改了名字,它就被破坏了。如果你移动了造成错误的函数调用,放到了一个共享的工具函数中,它也被破坏了。在更深一层的堆栈上发生异常,就会使这样的结构变得更脆弱。OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
在深入讨论这一话题前,让我先附带说明两个不能做承诺的事情。首先,异常并不能处理你所遇到的所有异常。这并不是一个稳固指导方法,但我喜欢为错误条件抛出异常,这些错误条件如果不立即处理或者报告,可能会在后期产生更严重的问题。例如,数据库里的数据完整性的错误,就应该生产一个异常。这个问题如果忽略就只会越发严重。而像在写入用户的窗口位置失败时,不太像是在后来会产生一系列的问题。返回一个错误代码来指示失败就足够了。OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
其次,写一个抛出(throw)语句并不意味会在这个时间创建一个新的异常类。我推荐创建更多的异常,而不是只有少数几个常规的自然异常:很从人好像在抛出异常时只对System.Exception情有独钟。可惜只只能提供最小的帮助信息来处理调用代码。相反,考虑创建一些必须的异常类,可以让调用代码明白是什么情况,而且提供了最好的机会来恢复它。OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
再说一遍:实际上要创建不同的异常类的原则,而且唯一原因是让你的用户在写catch语句来处理错误时更简单。查看分析这些错误条件,看哪些可以放一类里,成为一个可以恢复错误的行为,然后创建指定的异常类来处理这些行为。你的应用程序可以从一个文件或者目录丢失的错误中恢复过来吗?它还可以从安全权限不足的情况下恢复吗?网络资源丢失又会怎样呢?对于这种遇到不同的错误,可能要采取不同的恢复机制时,你应该为不同的行为创建新的异常类。OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
因此,现在你应该创建你自己的异常类了。当你创建一个异常类时,你有很多责任要完成。你应该总是从System.ApplicationException类派生你的异常类,而不是System.Exception类。对于这个基类你不用添加太多的功能。对于不同的异常类,它已经具有可以在不同的catch语句中处理的能力了。OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
但也不要从异常类中删除任何东西。ApplicationException 类有四个不同的构造函数:OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
// Default constructorOÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
public ApplicationException( );OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
// Create with a message.OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
public ApplicationException( string );OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
// Create with a message and an inner exception.OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
public ApplicationException( string, Exception );OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
// Create from an input stream.OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
protected ApplicationException(OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
SerializationInfo, StreamingContext );OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
当你创建一个新的异常类时,你应该创建这个四构造函数。不同的情况调用不同的构造方法来构造异常。你可以委托这个工作给基类来实现:OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
public class MyAssemblyException :OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
ApplicationExceptionOÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
{OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
public MyAssemblyException( ) :OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
base( )OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
{OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
}OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
public MyAssemblyException( string s ) :OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
base( s )OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
{OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
}OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
public MyAssemblyException( string s,OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
Exception e) :OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
base( s, e )OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
{OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
}OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
protected MyAssemblyException(OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
SerializationInfo info, StreamingContext cxt ) :OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
base( info, cxt )OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
{OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
}OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
}OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
构造函数须要的这个异常参数值得讨论一下。有时候,你所使用的类库之一会发生异常。调用你的库的代码可能会取得最小的关于可能修正行为的信息,当你简单从你使用的异常上传参数时:OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
public double DoSomeWork( )OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
{OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
// This might throw an exception definedOÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
// in the third party library:OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
return ThirdPartyLibrary.ImportantRoutine( );OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
}OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
当你创建异常时,你应该提供你自己的库信息。抛出你自己详细的异常,以及包含源异常做为它的内部异常属性。你可以提供你所能提供的最多的额外信息:OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
public double DoSomeWork( )OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
{OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
try {OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
// This might throw an exception definedOÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
// in the third party library:OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
return ThirdPartyLibrary.ImportantRoutine( );OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
} catch( Exception e )OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
{OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
string msg =OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
string.Format("Problem with {0} using library",OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
this.ToString( ));OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
throw new DoingSomeWorkException( msg, e );OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
}OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
}OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
}OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
这个新的版本会在问题发生的地方创建更多的信息。当你已经创建了一个恰当的ToString()方法时,你就已经创建了一个可以完整描述问题发生的异常对象。更多的,一个内联异常显示了产生问题的根源:也就是你所使用的第三方库里的一些信息。OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
这一技术叫做异常转化,转化一个底的层异常到更高级的异常,这样可以提供更多的关于错误的内容。你越是创建多的关于错误的额外的信息,就越是容易让它用于诊断,以及可能修正错误。通过创建你自己的异常类,你可能转化底层的问题到详细的异常,该异常包含所详细的应用程序信息,这可以帮助你诊断程序以及尽可能的修正问题。OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
希望你的应用程序不是经常抛出异常,但它会发生。如果你不做任何详细的处理,你的应用程序可能会产生默认的.Net框架异常,而不管是什么错误在你调用的方法里发生。提供更详细的信息将会让你以及你的用户,在实际应用中诊断程序以及可能的修正错误大有帮助。当且仅当对于错误有不同的行为要处理时,你才应该创建不同的异常类。你可以通过提供所有基类支持的构造函数,来创建全功能的异常类。你还可以使用InnerException属性来承载底层错误条件的所有错误信息。OÚÁŠÎ ÑO‘pwww.netcsharp.cn¦· ½¶™ ( b
posted @ 2009-12-19 16:21    阅读(2141)  评论(0编辑  收藏  举报