如何编写一个函数来调用另一个函数并捕获一些异常?

时间:2009-08-19 05:40:49

标签: c# .net exception

我有一系列具有不同参数签名的函数:

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操作失败的情况下报告成功和错误消息。 (请参阅更新的代码段。)

5 个答案:

答案 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);
}

这在我的眼中是更清晰,控制的流程是明确的。它不再是代码行,而且更易于维护。似乎普遍认为异常使代码不清楚 - 我只是不同意。

注意:捕获异常的想法引起了一些争论。让我澄清几点。

  1. 捕捉异常本身并不是邪恶的,但是如果你捕捉到异常是非常重要的,那么你就做对了。这些问题在question

  2. 中讨论
  3. 我不提倡任何例外的静默吞噬,最不重要的是系统异常。对于每个捕获的异常,需要决定是否记录消息,通常记录是最简单的事情。在考虑的情况下,我们正在捕获异常,以便我们可以考虑常见的处理。这不是通常的事情,但是如果我们做正确的事情,那么捕捉异常并不是本质上的错误。不要盲目遵守“不要捕捉异常”等规则。

  4. callExceptionReporter()的实现负责做正确的事情。对于特定于应用程序的异常,可以准备错误结果。对于其他例外,它可以简化重新抛出。

  5. 某些例外情况无法获取。示例来自.Net 2.0 StackOverflowException(通常)不可捕获。这对我们的代码没有任何影响,我们没有抓住它,我们不想抓住它。

  6. 有人建议通过捕捉异常,我们可能会开辟一些可能导致最终阻止行为不端的行为。这根本不是那么回事。最后在我们的异常处理程序到达之前很久就阻止了。如果最终行为不端,那就不会使用这种捕获物。如果我们达到这个问题,因为finally块会引发异常,无论它是另一个处理或重新抛出的例外。

  7. 回到原始问题如果您希望/需要继续执行您的计划,那么正如所观察到的那样,将实际的异常处理因素归结为其自己的功能。然后你写了最小的重复代码。

    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)

有一个类来处理应用程序中可能发生的所有可能异常。从该类中公开一个将处理异常的方法。该方法可以接受异常类型,它发生的位置等类型的参数并相应地处理它们。

在您拥有的一系列方法中,只需在异常处理类中调用该方法。