Reputation: 435
I have a validate method that called some other implements:
public ValidationResult Validate(Some arg) {
var errors = new List<ValidationError>();
validate1(arg, errors);
if (errors.Count > 0) {
return ValidationResult.Failed(errors);
}
validate2(arg, other, errors);
if (errors.Count > 0) {
return ValidationResult.Failed(errors);
}
validate3(arg, other2, errors);
if (errors.Count > 0) {
return ValidationResult.Failed(errors);
}
return ValidationResult.Succeess();
}
I want some way to make the code like below, use for loop to invoke each validator:
public ValidationResult Validate(Some arg) {
var errors = new List<ValidationError>();
var validators = new [] {
validate1(arg, errors),
validate2(arg, other, errors),
validate3(arg, other2, errors)
};
foreach (var validator in validators) {
validator.invoke();
if (errors.Count > 0) {
return ValidationResult.Failed(errors);
}
}
return ValidationResult.Success();
}
How can I do it?
Upvotes: 2
Views: 340
Reputation: 435
Thanks @tym32167 !
And I have some additional about async:
var validations = new Func<Task>[]
{
async () => await ValidateAsync(arg, other, errors)
};
foreach (var validation in validations)
{
await validation();
if (errors.Count > 0)
{
return ValidationResult.Failed(errors);
}
}
Upvotes: 0
Reputation: 9463
You could define a common interface for the validators and implement a class for each usecase.
public interface IValidator {
ValidationResult Invoke();
}
public class Validator1 : IValidator {
private string _arg;
private List<ValidationError> _errors;
Validator1(string arg, List<ValidationError> errors) {
_arg = arg;
_errors = errors
}
public ValidationResult Validate() {
if (_errors.Count > 0) {
return ValidationResult.Failed(_errors);
}
return ValidationResult.Success();
}
}
Then you can work with a list of IValidator instances.
public ValidationResult Validate(Some arg) {
var errors = new List<ValidationError>();
var validators = new IValidator[] {
new Validator1(arg, errors),
new Validator2(arg, other, errors),
new Validator3(arg, other2, errors)
};
foreach (var validator in validators) {
var result = validator.Invoke();
if (result != ValidationResult.Success()) {
return result;
}
}
return ValidationResult.Success();
}
Upvotes: 1
Reputation: 7546
Well, I consider implementing validation in Fluent-like style:
public interface IValidator<T>
{
IEnumerable<ValidationError> Validate(T obj);
IEnumerable<ValidationError> ValidateAll(IEnumerable<T> obj);
}
public class SomeTypeValidator : IValidator<SomeType>
{
private readonly IValidator<SomeNestedType> _validator1;
public SomeTypeValidator(IValidator<SomeNestedType> validator1)
{
_validator1 = validator1;
}
public IEnumerable<ValidationError> Validate(SomeType obj)
{
yield return Error("My first error");
foreach(var e in _validator1.Validate(obj.val1))
{
yield return e;
}
/*whatever you desire goes here*/
}
public IEnumerable<ValidationError> ValidateAll(IEnumerable<SomeType> objs)
{
return objs.SelectMany(Validate);
}
}
Then some useful extension:
public static void ThrowIfInvalid(this IEnumerable<ValidationError> errors)
{
if(errors == null)
return;
var e = errors.ToList();
if(e.Any())
{
throw new Exception(\*use 'e' here to form exception*\);
}
}
Then somewhere in code I call it like this:
_validator.Validate(new SomeType()).ThrowIfInvalid();
This way you will free yourself from those lists/packs of errors all over the place and just redirect validation error streams to whatever other validator you desire. Also you always can stop validation at some point, by calling yield break
and will be able to create ansamble from them.
Upvotes: 0
Reputation: 4891
You can try this
var validators = new Action[] {
()=>validate1(arg, errors),
()=>validate2(arg, other, errors),
()=>validate3(arg, other2, errors)
};
foreach (var v in validators)
v();
Upvotes: 7