我有一个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; }
}
答案 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等。如果它在任何时候失败,验证器会修饰错误消息并返回,因为不需要进一步验证。
而且,作为一个额外的好处,如果您这样做,您的验证不是通过静态方法完成的,因此您可以对验证代码的消费者进行单元测试。