7

いくつかの調査を行うと、パブリック メソッドへの引数は検証されるべきであるが、プライベート関数は通常検証されないことに、人々は一般的に同意しているようです。これにより、いくつかの疑問が生じますが、これまでのところ満足のいく答えを見つけることができませんでした.

例:

public void DoSomething(int i)
{
    if (i < 0)
        throw new ArgumentOutOfRangeException("i");

    double d = DoWork(i);
}

private double DoWork(int i)
{
    double ret = ...; // some calculation
    return ret;
}

考え:

  1. i内部で非負であるという要件が変更された場合はどうなりますDoWork()か? この設計は、時代遅れの検証チェックを残すリスクがあります。プログラマーは、変更された関数の使用法を調整する責任がありますが、エラーのリスクを最小限に抑えるためのより良い方法があるかどうか疑問に思っています。

  2. DoWork()not からの異なる呼び出しはどうDoSomething()ですか? 引数を重複して検証する必要がありますか?

public void DoSomething(int i)
{
    if (i < 0)
        throw new ArgumentOutOfRangeException("i");

    double d = DoWork(i);
}

public void DoSomethingElse()
{
    int i = 5;
    if (i < 0)
        throw new ArgumentOutOfRangeException("i");

    double d = DoWork(i);
}

private double DoWork(int i)
{
    double ret = ...; // some calculation
    return ret;
}

これは、チェックを独自の関数に入れることで少しきれいにすることができます。次に、 を呼び出す新しい関数がDoWork(int i)を検証するのを忘れるリスクがありiます。

public void DoSomething(int i)
{
    ThrowIfIntegerIsNegative(i);

    double d = DoWork(i);
}

public void DoSomethingElse()
{
    int i = 5;
    ThrowIfIntegerIsNegative(i);

    double d = DoWork(i);
}

static void ThrowIfIntegerIsNegative(int i)
{
    if (i < 0)
        throw new ArgumentOutOfRangeException("i");
}

private double DoWork(int i)
{
    double ret = ...; // some calculation
    return ret;
}

それはこれよりも優れていますか?

public void DoSomething(int i)
{
    double d = DoWork(i);
}

public void DoSomethingElse()
{
    double d = DoWork(5);
}

private double DoWork(int i)
{
    if (i < 0)
        throw new ArgumentOutOfRangeException("i");

    double ret = ...; // some calculation
    return ret;
}

状況に応じて、これらは私が同時に達成しようとしているいくつかの目標です。

  1. 引数の検証を 1 か所で行います (場合によっては、引数を使用する関数内)。
  2. 遅かれ早かれエラーを報告します (不適切なユーザー入力のために最後に失敗するためだけに、大量のコードを 1 時間実行したくない場合があります)。
  3. 引数を複数回検証しない
  4. リリース コードでのパフォーマンスへの影響を回避する

どのようにバランスを取りますか?どの方法論があなたにとって最も効果的でしたか? 洞察をいただければ幸いです。

4

3 に答える 3

2

パブリック メソッドで例外を検証するのが好きです。

public void Foo(int i)
{
    if (i < 0)
      throw new ArgumentOutOfRangeException("i");

    double d = DoWork(i);
}

そして、プライベート メソッドでアサートを使用して検証するのが好きです。

private double DoWork(int i)
{
    System.Diagnostics.Debug.Assert(i >= 0);
    // ....
}
  1. これは、複数の public メソッドで検証が重複していることを意味します。
  2. 無効なパラメーターをできるだけ早くキャッ​​チします。
  3. プライベート メソッド内の無効なパラメーターによる例外のスローArgumentOutOfRangeExceptionは、パラメーター名の違いなどにより、パブリック メソッドの呼び出し元を混乱させる可能性があります。
  4. 多くの場合、パブリック メソッドは、プライベート メソッドを呼び出す前に追加の作業を行うため、作業が節約されます。
  5. 単体テストを使用して、新しいメソッドが検証チェックを見逃さないようにします。

もう 1 つ行うべきことは、保護されたメソッドをパブリック メソッドのように扱うことです。

編集:

これは、上記の #3 に違反する不適切な検証の例です。

public void Foo(int distanceInMetres)
{
    double d = DoWork(distanceInMetres * 1000);
}

private double DoWork(int distanceInMillimetres)
{
    if (distanceInMillimetres < 0)
      throw new ArgumentOutOfRangeException("distanceInMillimetres");
    // ....
}

呼び出し元がFooパラメーター "distanceInMillimetres" で例外を確認した場合、"distanceInMetres" という名前のパラメーターを取った "Foo" を呼び出したため、呼び出し元は混乱します。

于 2013-06-06T18:25:26.173 に答える
1

public メソッドではなく public メソッドに関する dasblinkenlight のステートメントに同意します。

TDD を実践している場合、プライベート メソッドは、コードをリファクタリングし、パブリック メソッドの一部をプライベート メソッドに抽出した結果にすぎません。したがって、パブリック メソッドをテストでカバーした場合、プライベート メソッドは自動的にテストされます。

TDD を使用しないが、ロジックに違反していないことを確認したい場合は、アサート ( http://msdn.microsoft.com/en-us/library/ttcc4x86.aspx ) またはコードなど、さまざまな手法を使用できます。契約 ( http://msdn.microsoft.com/en-us/library/dd264808.aspx )。

于 2013-06-06T18:40:11.077 に答える