2

我已经在各种项目上遇到了这个问题几次,我想知道是否有比通常最终使用的解决方案更好的解决方案。假设我们有一系列需要执行的方法,并且我们想知道某个方法中是否出现了问题,并且可以正常打破(可能会撤销之前的更改...),但我通常会这样做以下(伪C#,因为它是我最熟悉的):错误处理的设计模式

private bool SomeMethod() 
{ 
    bool success = true; 
    string errorMessage = null; 
    success = TestPartA(ref errorMessage); 
    if (success) 
    { 
     success = TestPartB(ref errorMessage); 
    } 
    if (success) 
    { 
     success = TestPartC(ref errorMessage); 
    } 
    if (success) 
    { 
     success = TestPartD(ref errorMessage); 
    } 
     //... some further tests: display the error message somehow, then: 
     return success; 
} 

private bool TestPartA(ref string errorMessage) 
{ 
    // Do some testing... 
    if (somethingBadHappens) 
    { 
     errorMessage = "The error that happens"; 
     return false; 
    } 
    return true; 
} 

我只是想知道(这是我的问题),如果有对于这种事情的应对更好的方法。我似乎最终写了很多if声明,看起来应该是很冷静的。

我已经被建议循环使用一组委托函数,但是我担心会过度设计解决方案,除非有一个干净的方法来做到这一点。

+1

如果这些确实是错误,那么你应该抛出异常。 – Polyfun

回答

6

我想你应该使用异常。请注意,您通常应该仅在您的应用程序的“顶级”捕捉异常。

private void TopLevelMethod() 
{ 
    try 
    { 
     SomeMethod(); 
    } 
    catch (Exception ex) 
    { 
     // Log/report exception/display to user etc. 
    } 
} 

private void SomeMethod() 
{ 
    TestPartA(); 
    TestPartB(); 
    TestPartC(); 
    TestPartD(); 
} 

private void TestPartA() 
{ 
    // Do some testing... 
    try 
    { 
     if (somethingBadHappens) 
     { 
      throw new Exception("The error that happens"); 
     } 
    } 
    catch (Exception) 
    { 
     // Cleanup here. If no cleanup is possible, 
     // do not catch the exception here, i.e., 
     // try...catch would not be necessary in this method. 

     // Re-throw the original exception. 
     throw; 
    } 
} 

private void TestPartB() 
{ 
    // No need for try...catch because we can't do any cleanup for this method. 
    if (somethingBadHappens) 
    { 
     throw new Exception("The error that happens"); 
    } 
} 

我在我的例子中使用了内建的System.Exception类;您可以创建自己的派生异常类,或者使用从System.Exception派生的内置派生类。

+0

我认为你是对的;感谢ShellShock。我从来没有想过抛出我自己的异常/重新抛出异常,这几乎涵盖了所有情况。 – loxdog

2

我尝试坚持一种被称为“快速失败”的原则;方法应该在应该失败时立即失败,并立即返回错误的详细信息。调用方法,然后适当地响应(异常重新抛出它的调用者,记录细节,显示一个错误,如果它是一个用户界面绑定的方法等): -

http://en.wikipedia.org/wiki/Fail-fast

然而,这并不意味着使用异常来控制应用程序的流程。只是抛出一个异常,当你可能处理它一般是不好的做法: -

http://msdn.microsoft.com/en-us/library/dd264997.aspx

在你的情况,我会重新写你的代码(例如): -

private bool SomeMethod() 
{ 
    bool success = false; 

    try 
    { 
     TestPartA(); 
     TestPartB(); 
     TestPartC(); 
     TestPartD(); 

     success = true; 
    } 
    catch (Exception ex) 
    { 
     LogError(ex.Message); 
    } 

    //... some further tests: display the error message somehow, then: 
    return success; 
} 

private void TestPartA() 
{ 
    // Do some testing... 
    if (somethingBadHappens) 
    { 
     throw new ApplicationException("The error that happens"); 
    } 
} 
+0

与ShellShock几乎相同的答案,只是慢一点!尽管我喜欢快速失败的原则,无价的阅读。 – loxdog

+1

从msdn:_“你应该从Exception类而不是ApplicationException类派生自定义异常,你不应该在你的代码中抛出一个ApplicationException异常,除非你打算重新抛出原来的异常,否则你不应该捕获ApplicationException异常。“_ – Gusdor

4

您可以尝试查看"Open/Closed" section of the SOLID Principle.在您的示例中,您可以创建一个ITestRule界面,其中包含一个名为CheckRule()的方法,该方法将更新您的消息并返回bool。然后,您将为每个要测试的规则创建接口实现,并将该类添加到List<ITestRule>对象。从上面的例子Redmondo,我会改变为以下:

var discountRules = 
       new List<ITestRule> 
        { 
         new TestPartA(), 
         new TestPartB(), 
         new TestPartC(), 
         new TestPartD(), 
        }; 

你会然后通过新List<ITestRule>至将循环遍历每个类的并运行CheckRule()方法的评估。

+0

这会起作用(未来我可能会需要类似的东西),但我认为我会为我所需要的过度设计而犯内疚。 – loxdog