我有一系列具有不同参数签名的函数:
public void function1 (string s1, string s1, string s3, string s4) {...}
public void function2 (int i1, int i2, string s3, string s4) {...}
public void function3 (int i1, string s2, int i3, string s4) {...}
.
.
etc //some 30 odd functions
调用每个函数可能抛出一组异常,如TimeoutException,CommunicationException等(是的,这些是WCF代理函数)
现在我必须将这些调用包装在try catch块中,但DRY原则说我写错了很多相同的try catch块:
public void Interfacefunction1 (...) {
try {
function1 (...);
}
catch (TimeoutException) {
taskResult.Success = false;
taskResult.Message = Resources.ServerConnectionBroke;
}
catch (CommunicationException) {
taskResult.Success = false;
taskResult.Message = Resources.CommunicationFailed;
}
}
//and...
public void Interfacefunction2 (...) {
try {
function2 (...);
}
catch (TimeoutException) {
taskResult.Success = false;
taskResult.Message = Resources.ServerConnectionBroke;
}
catch (CommunicationException) {
taskResult.Success = false;
taskResult.Message = Resources.CommunicationFailed;
}
}
//etc
有没有办法编写一个函数来调用这些函数并在抛出时捕获异常?
编辑:
我无法控制将要调用它们的接口函数序列。这些所有功能都暴露给用户(另一个程序员),用户可以按照自己喜欢的顺序调用任何一个,两个或多个。我只需要在EACH操作失败的情况下报告成功和错误消息。 (请参阅更新的代码段。)
答案 0 :(得分:8)
你可以使用lambdas:
CatchCommonExceptions(() => function1(...));
private void CatchCommonExceptions(Action action)
{
try
{
action ();
}
catch (TimeoutException) {
taskResult.Success = false;
taskResult.Message = Resources.ServerConnectionBroke;
}
catch (CommunicationException)
{
taskResult.Success = false;
taskResult.Message = Resources.CommunicationFailed;
}
}
你可以拥有一个Func< T>为那些返回值的人重载。
编辑:您可以查看complete source here。
答案 1 :(得分:4)
捕获异常后会发生什么?你能重构一下吗?通常,您可以在概念上将try catch放在不同的级别。
processUserRequest() {
try {
if (function1() )
function2()
function3()
... etc
prepare success response to user
} catch (TimeOutException ) {
log message
prepare fail response to user
} catch ... etc
}
send response
}
还可以减少需要捕获的异常数量吗?在Java中,我倾向于使用异常的层次结构。我有一个TransientException,当它合理地期望重试相同的请求工作时抛出。 Timeout和Communication异常是TransientException的子类,所以我只需要捕获TransientrException。类似地,我有一个InvalidRequestException - 您可以根据需要多次发出无效请求但它永远不会工作!因此,我可以为诸如格式错误的SQL之类的情况继承InvalidRequestException。
回应您的进一步解释:
您的意图是包装每个函数,以便调用者可以检查成功代码而不是捕获异常。希望呼叫者将编码
Response result = function1( ... ) ;
if ( result.isError() ) {
do something with result.reason();
} else {
maybe do something with the answer
}
首先让我说,为什么要这么麻烦?他们可以用一个区块捕获所有异常。
try {
function1( ... )
maybe do somethign with the annswer
}
catch(Exception e) {
callExceptionReporter(e);
}
这在我的眼中是多更清晰,控制的流程是明确的。它不再是代码行,而且更易于维护。似乎普遍认为异常使代码不清楚 - 我只是不同意。
注意:捕获异常的想法引起了一些争论。让我澄清几点。
捕捉异常本身并不是邪恶的,但是如果你捕捉到异常是非常重要的,那么你就做对了。这些问题在question。
我不提倡任何例外的静默吞噬,最不重要的是系统异常。对于每个捕获的异常,需要决定是否记录消息,通常记录是最简单的事情。在考虑的情况下,我们正在捕获异常,以便我们可以考虑常见的处理。这不是通常的事情,但是如果我们做正确的事情,那么捕捉异常并不是本质上的错误。不要盲目遵守“不要捕捉异常”等规则。
callExceptionReporter()的实现负责做正确的事情。对于特定于应用程序的异常,可以准备错误结果。对于其他例外,它可以简化重新抛出。
某些例外情况无法获取。示例来自.Net 2.0 StackOverflowException(通常)不可捕获。这对我们的代码没有任何影响,我们没有抓住它,我们不想抓住它。
有人建议通过捕捉异常,我们可能会开辟一些可能导致最终阻止行为不端的行为。这根本不是那么回事。最后在我们的异常处理程序到达之前很久就阻止了。如果最终行为不端,那就不会使用这种捕获物。如果我们达到这个问题,因为finally块会引发异常,无论它是另一个处理或重新抛出的例外。
回到原始问题如果您希望/需要继续执行您的计划,那么正如所观察到的那样,将实际的异常处理因素归结为其自己的功能。然后你写了最小的重复代码。
try {
return function1( ... )
}
catch(Exception e) {
return prepareExceptionResponse(e);
}
只要你在prepareExceptionResponse()中做正确的事情,重新抛出低级异常就不会造成任何伤害。 cathc Exception在这个级别上是不寻常的,但是你有一个特殊的需要 - 做一些常见的异常处理。
答案 2 :(得分:1)
您每次都必须调用每个函数并捕获异常。但是,如果您使用Exception Handling Block中的Enterprise Library之类的内容,则可以使代码更清晰。这样,您可以为失败的WCF调用设置策略,而不必单独处理每种不同类型的异常。
答案 3 :(得分:0)
我自己没有核实过,但我刚才想出了以下内容:
try {
function1 (...);
}
catch (Exception ex) {
//this will not catch all the exception types even though it may look like :)
HandlingWCFExceptions(ex, taskResult);
}
....
private void HandlingWCFExceptions(Exception ex, TaskResult result)
{
try {
//This will preserve the original exception status including call stack
throw;
}
catch (TimeoutException) {
taskResult.Success = false;
taskResult.Message = Resources.ServerConnectionBroke;
}
catch (CommunicationException) {
taskResult.Success = false;
taskResult.Message = Resources.CommunicationFailed;
}
//catch other (WCF) exception types that you can handle safely
//Any other exception not caught here will bubble up
...
}
这个可以与任何具有不同参数和返回类型的funtionN()
很好地协作,尤其是当您对WCF服务没有任何控制时。
答案 4 :(得分:-1)
有一个类来处理应用程序中可能发生的所有可能异常。从该类中公开一个将处理异常的方法。该方法可以接受异常类型,它发生的位置等类型的参数并相应地处理它们。
在您拥有的一系列方法中,只需在异常处理类中调用该方法。