我有一些项目 - 我们只需称呼他们itemA
,itemB
,itemC
和itemD
- 我想验证他们每个人都使用我写过的验证方法。
验证方法的返回类型和签名如下:
public async Task<ValidationMessage> ValidateItem(MyClass item);
ValidationMessage
是一个简单的类:
public class ValidationMessage
{
public bool Success { get; set; }
public string ErrorMessage { get; set; }
}
要验证每个项目,目前我有以下代码:
ValidationMessage result = new ValidationMessage();
result = await this.ValidateItem(itemA);
if (!result.Success)
{
return result;
}
result = await this.ValidateItem(itemB);
if (!result.Success)
{
return result;
}
result = await this.ValidateItem(itemC);
if (!result.Success)
{
return result;
}
result = await this.ValidateItem(itemD);
return result;
正如您所看到的,只要其中一个项目未通过验证方法(意为result.Success == false
),我就会返回,并且不会继续验证其余项目。
我认为重复分配结果和重复的if语句有点乏味/丑陋。我希望有一些现有的c#class / construct(也许LINQ可以帮助)更简洁地写这个。我编写了以下内容来展示我的想法:
ValidationMessage result = new ValidationMessage();
result = await this.ValidateItem(itemA).ContinueConditional(
(r => r.Success) => await this.ValidateItem(itemB).ContinueConditional(
(r => r.Success) => await this.ValidateItem(itemC).ContinueConditional(
(r => r.Success) => await this.ValidateItem(itemD))));
return result;
基本上,this.ValidateItem(itemA)
的返回值已分配给result
,然后此值会转到ContinueConditional
。如果结果r
具有Success == true
,则继续验证itemB
,依此类推。如果它不成功,则退出该代码并直接进入底部的return语句,从而返回未通过验证的项目。如果所有项目都经过验证,那么无论如何都会转到该返回语句。
我为长篇文章道歉,特别是如果c#构造已经存在并且很明显。我很感激任何帮助。
注意:为了发布此内容,我简化了我的实例。简化的一个重要部分是itemA
,itemB
,itemC
和itemD
不是同一类型,尽管它们被称为上面的方法签名中的MyClass
。所以我不能把它们放在一个列表中并使用LINQ。这也意味着我实际上有不同的验证方法来接受我所拥有的各种项目,但我并不想在顶部解释所有这些,以防它过于复杂。重要的是,他们都返回ValidationMessage
。
答案 0 :(得分:3)
如何在检查成功/失败时反转逻辑?
ValidationMessage result = await this.ValidateItem(itemA);
if (result.Success) result = await this.ValidateItem(itemB);
if (result.Success) result = await this.ValidateItem(itemC);
if (result.Success) result = await this.ValidateItem(itemD);
return result;
答案 1 :(得分:2)
这个怎么样?您可以根据需要将其扩展为任意数量的元素。
var validationRules = new List<Func<Task<bool>>>(){
() => ValidateItem(itemA),
() => ValidateItem(itemB),
() => ValidateItem(itemC),
() => ValidateItem(itemD),
};
ValidationMessage result = new ValidationMessage();
foreach(var validationRule in validationRules)
{
result = await validationRule();
if(!result)
return result;
}
return result;
答案 2 :(得分:2)
您可以使用FluentValidation创建自定义规则以循环浏览要验证的模型列表。这比其他答案的开销更大,但它是一个干净可读代码的好方法。
首先定义您的共享模型
public class YourSharedModel()
{
List<MyClass> Models = new List<MyClass>();
}
定义验证器:
public class SharedModelValidator : AbstractValidator<YourSharedModel>
{
public SharedModelValidator()
{
CustomRule(BeValid)
}
public bool BeValid(ValidationErrors<YourSharedModel> validationFailures, YourSharedModel sharedModel, ValidationContext<YourSharedModel> validationContext)
{
for (var m in sharedModel.Models)
{
var result = YourValidationMethod(m);
if (!result.Success)
{
validationFailures.AddFailureFor(x => m, result.ErrorMessage);
return false;
}
}
return true;
}
private YourValidationMethod(MyClass model)
{
// the code you have that actually validates
}
}
实施将类似于:
var yourSharedModel = new YourSharedModel();
yourSharedModel.Models.Add(itemA);
yourSharedModel.Models.Add(itemB);
// etc
var validator = new SharedModelValidator();
var results = validator.Validate(yourSharedModel);
if (!results.IsValid)
{
// do something with results.Errors
}
您还可以保留所有错误并在循环后返回false,以便您在提交时一次性获取所有错误,而不是逐个获取错误,当然,这是假设来自Web应用程序的表单发布。提供更好的用户友好体验。
答案 3 :(得分:1)
您可以使用界面,然后将您的项目添加到foreach
到
ValidationMessage Test()
{
List<IValidatable> items = new List<IValidatable>();
MyClass1 item1 = new MyClass1();
MyClass2 item2 = new MyClass2();
items.Add(item1);
items.Add(item2);
ValidationMessage result = null;
foreach (var i in items)
{
result = i.ValidateItem();
if (!result.Success) break;
}
return result;
}
interface IValidatable
{
ValidationMessage ValidateItem();
}
public class ValidationMessage
{
public bool Success { get; set; }
public string ErrorMessage { get; set; }
}
public class MyClass1 : IValidatable
{
public ValidationMessage ValidateItem()
{
return new ValidationMessage();
}
}
public class MyClass2 : IValidatable
{
public ValidationMessage ValidateItem()
{
return new ValidationMessage();
}
}
答案 4 :(得分:1)
另一种(也许是正统的)方法是超载&amp;&amp; ValidationMessage上的运算符:
public class ValidationMessage
{
public bool Success { get; set; }
public string ErrorMessage { get; set; }
public static ValidationMessage operator &(ValidationMessage message1, ValidationMessage message2)
{
return message1.Success ? message2 : message1;
}
public static ValidationMessage operator |(ValidationMessage message1, ValidationMessage message2)
{
return message1.Success ? message1 : message2;
}
public static bool operator true(ValidationMessage message)
{
return message.Success;
}
public static bool operator false(ValidationMessage message)
{
return !message.Success;
}
}
然后你可以这样做:
return (await this.ValidateItem(ItemA)) &&
(await this.ValidateItem(ItemB)) &&
(await this.ValidateItem(ItemC)) &&
(await this.ValidateItem(ItemD));