如何避免参数验证

时间:2009-10-22 17:24:30

标签: c# argument-validation

验证原始参数和“复杂数据”

验证参数

编写方法时,应在执行任何操作之前首先验证参数。例如,假设我们有一个代表人的类:

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类出了什么问题?在将值设置为Person字段之前,不验证名称和年龄。 “验证?”是什么意思?应该检查两个参数,它们的值是可接受的。例如,如果name的值是空字符串怎么办?或者年龄的值是-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的构造函数接收的参数。

Tedium ad Nauseum

因为你已经在很长一段时间内验证了参数(对吗?),你可能已经厌倦了写这些if(....)在你的所有方法中抛出Argument ...语句。

我们可以做些什么来避免在整个代码中写入String.IsNullOrEmpty几十亿次?

5 个答案:

答案 0 :(得分:6)

您可以查看Code Contracts in .NET 4.0

如果您不想等待代码合同,您可能还需要查看FluentValidation Library on CodePlex

最终,您仍然需要将控制参数值的规则放在某处 - 这只是决定您是否更喜欢命令式样式(例如string.IsNullOrEmpty)或声明性样式。

验证输入是编写可靠代码的关键实践 - 但它肯定是重复和冗长的。

答案 1 :(得分:2)

使用更复杂的类型而不是原语可能会对你有所帮助。

例如,如果您花时间定义类似PersonName类的内容,则可以在其中验证 ,而不必在其他所有内容上进行验证需要在其上有名称的对象。

显然,如果您有多个使用相同字段类型的对象,这只会有助于解决问题。

答案 2 :(得分:1)

您可以尝试使用Castle Validation Framework =&gt; http://www.castleproject.org/activerecord/documentation/v1rc1/usersguide/validation.html

OR

您可以使用我创建的简单验证框架。两个框架都使用基于属性的验证。请查看以下链接:

http://www.highoncoding.com/Articles/424_Creating_a_Domain_Object_Validation_Framework.aspx

答案 3 :(得分:1)

有基于Postsharp的选项。 code-o-matic就是其中之一。它允许你编写这样的代码:

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

我每天都在工作中使用它。

答案 4 :(得分:-1)

我将用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.
    }
}