5

プリミティブ引数と「複雑なデータ」の検証

引数の検証

メソッドを記述するときは、操作を実行する前に、まず引数を検証する必要があります。たとえば、人を表すクラスがあるとします。

public class Person
{
    public readonly string Name;
    public readonly int Age;

    public class Person(string name, int age)
    {
        this.Name = name;
        this.Age = age;
    }
}

この Person クラスの何が問題になっていますか? name と age は、値が Person のフィールドとして設定される前に検証されません。「検証済み」とはどういう意味ですか? 両方の引数をチェックして、その値が許容可能であることを確認する必要があります。たとえば、name の値が空の文字列の場合はどうなるでしょうか。それとも age の値が -10 ですか?

引数の検証は、値が受け入れられない場合に ArgumentExceptions または派生例外をスローすることによって実行されます。例えば:

public class Person(string name, int age)
{
    if (String.IsNullOrEmpty(name))
    {
        throw new ArgumentNullException
            ("name", "Cannot be null or empty.");
    }

    if (age <= 0 || age > 120)
    {
        throw new ArgumentOutOfRangeException
            ("age", "Must be greater than 0 and less than 120.");
    }

    this.Name = name;
    this.Age = age;
}

これにより、 Person のコンストラクターが受け取る引数が適切に検証されます。

退屈で吐き気がする

あなたは長い間引数を検証してきたので (そうですか?)、すべてのメソッドで if (....) throw Argument... ステートメントを書くのにうんざりしているでしょう。

コード全体で何億回も String.IsNullOrEmpty を記述しないようにするにはどうすればよいでしょうか?

4

5 に答える 5

6

.NET 4.0 の Code Contracts を調べることができます。

コード コントラクトを待ちたくない場合は、CodePlex の FluentValidation ライブラリを参照することもできます。

最終的には、引数の値を管理する規則をどこかに置く必要があります。それは、命令型のスタイル (string.IsNullOrEmpty など) と宣言型のどちらを好むかを決めるだけの問題です。

入力をそのまま検証することは、堅実なコードを記述するための重要なプラクティスですが、確かに反復的で冗長になる可能性があります。

于 2009-10-22T17:26:15.840 に答える
2

プリミティブではなく、より複雑な型を使用すると役立つ場合があります。

たとえば、時間をかけてPersonNameクラスのようなものを定義する場合、そこに検証を行うことができ、名前を付ける必要がある他のすべてのオブジェクトで検証を続ける必要はありません。

明らかに、これは同じフィールド タイプを使用する複数のオブジェクトがある場合にのみ問題を解決します。

于 2009-10-22T17:39:56.110 に答える
1

Postsharpに基づくオプションがあります。code-o-maticはその1つです。次のようなコードを記述できます。

public class Person(
    [NotNull, NotEmpty] string name,
    [NotNull, NotEmpty] int age
)
{
    this.Name = name;
    this.Age = age;
}

私はこれを仕事で毎日使っています。

于 2009-10-22T18:12:59.233 に答える
-2

Dプログラミング言語で解決策を提供します。私は C# を使用していないため、C# のジェネリックとバリアディックがどれほど強力かはわかりませんが、これを適応させることができるかもしれません。

void validate(T...)(T args) {  // args is variadic.
    foreach(arg; args) {  // Iterate over variadic argument list.
        static if(isSomeString!(typeof(arg))) {  // Introspect to see arg's type.
            if(arg.isNullOrEmpty) {
                throw new ArgException(
                    "Problem exists between keyboard and chair.");
            }
        } else static if(isOtherTypeWithBoilerPlateValidation!(typeof(arg))) {
            // Do more boilerplate validation.
        }
    }
}

使用法:

class Foo {
    SomeType myMethod(T arg1, U arg2, V arg3) {
        validate(arg1, arg2, arg3);

        // Do non-boilerplate validation.

        // Method body.
    }
}
于 2009-10-22T17:31:33.443 に答える