验证类及其集合属性的建议

时间:2012-02-07 17:48:23

标签: c#

我有一个Query类,它有许多属性,是其他对象的集合。作为验证Query对象的一部分,我想验证每个Query集合中的所有对象。到目前为止,我已经提出了三种方法来做到这一点。我想要反馈人们喜欢哪种方法以及任何其他可能的方法。

方法1

public static ValidationResult ValidateQuery(Query query)
{
    ValidationResult result;
    result = ValidateColumns(query);
    if (result.Passed)
    {
        result = ValidateFilters(query);
        if (result.Passed)
        {
            result = ValidateSortOrders(query);
        }
    }
    return result;
}

虽然集合属性的数量很少,但代码是可读的。但是如果我有更多的东西,我最终会得到很多嵌套的if语句,在我看来这会降低可读性。我尝试在接下来的两种方法中解决这个问题:

方法2

public static ValidationResult ValidateQuery(Query query)
{
    ValidationResult[] results = new ValidationResult[4];
    results[0] = ValidateColumns(query);
    results[1] = ValidateFilters(query);
    results[2] = ValidateGroups(query);
    results[3] = ValidateSortOrders(query);  
    return results.FirstOrDefault(item => !item.Passed) ?? results[0];
}

方法3

public static ValidationResult ValidateQuery(Query query)
{
    ValidationResult result = null;
    int i = 0;
    bool done = false;
    do
    {
        switch (i)
        {
            case 0: result = ValidateColumns(query); break;
            case 1: result = ValidateGroups(query); break;
            case 2: result = ValidateSortOrders(query); break;
            default: done = true; break;
        }
        ++i;
    } while (result.Passed && !done);
    return result ?? new ValidationResult(true, string.Empty);
}

如果您需要,ValidationResult类的定义:

public class ValidationResult
{
    public ValidationResult(bool passed, string message)
    {
        this.Passed = passed;
        this.ErrorMessage = message ?? string.Empty;
    }
    public string ErrorMessage {get; private set; }
    public bool Passed { get; private set; }
}

5 个答案:

答案 0 :(得分:3)

有什么问题
result = ValidateSomething();
if (!result.Passed)
    return result;

result = ValidateSomethingElse();
if (!result.Passed)
    return result;

也就是说,如果你真的只想返回一个错误。如果这是用于用户输入,则会导致相当烦人的界面。当用户犯了多个错误时,这个东西一次只能报告其中一个,并且用户必须一个接一个地进行修正,直到它们消失为止。

您是否考虑过返回一系列验证结果?您可以将集合传递给每个验证方法,并让它们将可能的错误添加到集合中。

避开while-switch

答案 1 :(得分:2)

我已经完成了类似于方法2的验证。但是,您可以执行以下操作:

,而不是使用数组
    public IEnumerable<ValidationResult> ValidateQuery(Query query)
    {
        if (!ValidateColumns(query)) yield return new ValidationResult("Bad columns");
        if (!ValidateFilters(query)) yield return new ValidationResult("Bad filters");
        if (!ValidateGroups(query)) yield return new ValidationResult("Bad groups");
        if (!ValidateSortOrders(query)) yield return new ValidationResult("Bad sort order");
    }

这种方法的好处是您不必对数组的大小进行硬编码,并且可以返回多个失败的验证。然后,您可以通过使用results.Any()

检查是否存在任何结果来设置“Passed”标志

答案 2 :(得分:2)

收益率回报怎么样?

IEnumerable<string> ValidateAll(Query query)
{
    if( !ValidateSomething() ) {
        yield return "Validate Something Failed...";
    }

    if( !ValidateSomethingelse() ) {
        yield return "Something else failed...";
    }
}

当然,可枚举类型不必是string

答案 3 :(得分:2)

您可以向And班级添加名为ValidationResult的方法:

public class ValidationResult
{
    public ValidationResult(bool passed, string message)
    {
        this.Passed = passed;
        this.ErrorMessage = message ?? string.Empty;
    }

    public ValidationResult And(ValidationResult other)
    {
        this.Passed &= other.Passed;
        this.Message += "\n" + other.Message;
        return this;
    } 
    public string ErrorMessage {get; private set; }
    public bool Passed { get; private set; }
}

然后你可以像这样使用它:

bool passed = ValidateColumns(query)
                  .And(ValidateGroups(query))
                  .And(ValidateSortOrders(query))
                   //...
                  .And(ValidateSomethingElse(query))
                  .Passed;

答案 4 :(得分:1)

如果优先顺序和验证数量可能会发生变化,您可以使用责任链模式:

http://www.dofactory.com/Patterns/PatternChain.aspx

而不是调用静态命名子方法的静态方法,您有一个基本验证器,每种验证都是一个知道链中下一个验证器的继承者。因此,ColumnValidator查看查询,如果好,则将其传递给GroupsValidator等。如果它在任何时候失败,验证器会修饰错误消息并返回,因为不需要进一步验证。

而且,作为一个额外的好处,如果您这样做,您的验证不是通过静态方法完成的,因此您可以对验证代码的消费者进行单元测试。