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

3

我有一个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];
}

方法三

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个回答

3

有什么问题

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

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

也就是说,如果你真的只想返回一个错误。如果这是针对用户输入的,那么它会导致一个非常烦人的界面。当用户发生多个错误时,它只能报告其中之一,用户必须一个接一个地进行更正,直到错误消失。

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

还要避免while-switch


除了我在可能的方法列表中漏掉它之外,它没有任何问题!这是我目前的做法。 - Ɖiamond ǤeezeƦ

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");
    }

该方法的好处在于您无需硬编码数组的大小,并且可以返回多个失败的验证。然后,通过检查是否存在任何结果,您可以设置“Passed”标志,使用results.Any()实现。

2

yield return是什么?

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

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

当然,可枚举类型不一定是一个字符串


2
您可以在您的ValidationResult类中添加一个名为And的方法:
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;

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

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

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

另外,如果以这种方式执行验证,则可以使用单元测试验证代码的消费者,从而获得额外的奖励。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接