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为一些看起来应该更流畅的东西写了很多陈述。

有人建议我对一组委托函数进行循环,但我担心这会过度设计解决方案,除非有一种干净的方法可以做到这一点。

4

3 回答 3

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 派生的内置异常类。

于 2014-01-31T09:51:02.863 回答
5

您也许可以尝试查看SOLID 原则的“打开/关闭”部分。在您的示例中,您也许可以创建一个ITestRule接口,其中包含一个调用方法,该方法CheckRule()将更新您的消息并返回一个bool. 然后,您将为要测试的每个规则创建一个接口实现,并将该类添加到List<ITestRule>对象中。从上面的 Redmondo 示例中,我将更改为以下内容:

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

然后,您会将 new 传递List<ITestRule>给评估器,该评估器将遍历每个类并运行该CheckRule()方法。

于 2014-01-31T09:58:57.863 回答
2

I try to stick to a principle known as 'Fail Fast'; methods should fail when they are supposed to, and return immediately with details of the error. The calling method then responds appropriately (re-throw the exception to its caller, log the details, show an error if it's a UI-bound method, etc): -

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

However, this does not mean using exceptions to control the flow of your application. Just raising an exception when you could deal with it is generally bad practice: -

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

In your case, I'd re-write your code as (for example): -

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");
    }
}
于 2014-01-31T09:53:47.297 回答