使用参数

问题描述:

C#委托我有一个叫一些其它工具一个validate方法:使用参数

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

我想一些办法让像下面的代码,使用循环调用每个校验:

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

我该怎么做?

+3

什么是'other'和'other2'? 'validate'是否有2个重载? – Sweeper

+4

使用数组或lambdas列表。如果您以前没有使用过它,则可以在网上获得的Microsoft文档是您的朋友。 – dumetrulo

+0

@Sweeper没有过载,它有三种不同的方法,它们有不同的参数列表。 –

你可以试试这个

var validators = new Action[] { 
    ()=>validate1(arg, errors), 
    ()=>validate2(arg, other, errors), 
    ()=>validate3(arg, other2, errors) 
}; 

foreach (var v in validators) 
    v(); 

你可以定义一个通用接口,用于验证和实现每个用例的类。

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

然后你可以使用一个IValidator实例列表。

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

好吧,我考虑流利般的风格实现验证:

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

那么一些有用的扩展代码

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*\); 
    } 
} 

然后某处我这样称呼它:

_validator.Validate(new SomeType()).ThrowIfInvalid(); 

通过这种方式,您可以将自己从错误列表/错误中解放出来,只需将验证错误流重定向到您所需的任何其他验证器即可。此外,您总是可以通过致电yield break停止验证,并且可以从中创建ansamble。

谢谢@ tym32167!

而且我有一些额外的约异步:

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