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 Principle の「Open/Closed」セクションを見てみるとよいでしょう。あなたの例ITestRuleではCheckRule()、メッセージを更新してbool. 次に、テストするルールごとにインターフェイスの実装を作成し、そのクラスをList<ITestRule>オブジェクトに追加します。上記のレドモンドの例から、次のように変更します。

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

List<ITestRule>次に、各クラスをループしてCheckRule()メソッドを実行するエバリュエーターにnew を渡します。

于 2014-01-31T09:58:57.863 に答える
2

私は「フェイル ファスト」として知られる原則に固執しようとしています。メソッドは、想定されているときに失敗し、エラーの詳細をすぐに返す必要があります。次に、呼び出し元のメソッドが適切に応答します (呼び出し元に例外を再スローし、詳細をログに記録し、UI バインド メソッドの場合はエラーを表示します): -

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