代码之家  ›  专栏  ›  技术社区  ›  Hemant

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

  •  2
  • Hemant  · 技术社区  · 15 年前

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

    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
    

    是否有任何方法可以编写一个函数来调用这些函数并在抛出时捕获异常?

    编辑:

    我无法控制将在其中调用它们的接口函数的顺序。这些所有的函数都向用户(另一个程序员)公开,用户可以按照自己喜欢的顺序调用任何一个、两个或多个函数。我只需要在每次操作失败时报告成功和错误消息。(请参见更新的代码段)。

    5 回复  |  直到 15 年前
        1
  •  8
  •   Hemant    15 年前

    您可以使用lambda:

    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 .

        2
  •  4
  •   Community CDub    8 年前

    捕捉到异常后会发生什么?你能重构吗?通常,在概念上,您可以将尝试捕获置于不同的级别。

     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,当它合理地期望对相同请求进行重试时抛出。超时和通信异常是TransientException的子类,所以我只需要捕获TransientException。同样,我也有一个InvalidRequestException——您可以根据自己的喜好多次提出无效的请求,但它永远不会起作用!因此,我可以将InvalidRequestException子类化为不正确的SQL等情况。

    根据您的进一步解释:

    您的目的是包装每个函数,以便调用者可以检查成功代码而不是捕获异常。希望来电者能编码

    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. CallExceptionReporter()的实现负责执行正确的操作。对于应用程序,特定的异常可以准备错误结果。对于其他例外情况,它可以简单地重新显示。

    4. 某些例外是不可捕捉的。.NET 2.0 StackOverflowException中的示例(通常)不可捕获。这对我们的代码没有影响,我们不捕捉它,我们不想捕捉它。

    5. 有人建议,通过捕获异常,我们可能会打开一些最终阻止不当行为的可能性。但事实并非如此。最后,在到达异常处理程序之前很久就阻止了激发。如果最终行为不端,那不是因为使用了这种捕获物。如果我们到达此catch是因为finally块抛出了异常,不管它只是要处理或重新引发的另一个异常。

    如果你想/需要继续你的计划,那么回到你原来的问题上,正如已经观察到的,把实际的异常处理考虑到它自己的功能中。然后您将编写最少的重复代码。

    try { 
        return function1( ... )
    }
    catch(Exception e) {
        return prepareExceptionResponse(e);
    }
    

    只要在PrepareExceptionResponse()中做正确的事情,重新引发低级异常,就不会造成任何伤害。在这个级别上,cathc异常是不常见的,但是您有一个特殊的需求——做一些常见的异常处理。

        3
  •  1
  •   JP Alioto    15 年前

    您将不得不调用每个函数并每次捕获异常。但是,如果使用类似 Exception Handling Block 在里面 Enterprise Library . 这样,您就可以为失败的WCF调用设置策略,而不必单独处理每种不同类型的异常。

        4
  •  0
  •   Chansik Im    15 年前

    我自己还没有证实,我只是想出了以下几点:

    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服务没有任何控制时。

        5
  •  -1
  •   danish    15 年前

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

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