带参数的 C# 委托
C# delegate with params
我有一个调用其他一些工具的验证方法:
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();
}
我想要一些方法来制作如下代码,使用 for 循环来调用每个验证器:
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();
}
我该怎么做?
你可以试试这个
var validators = new Action[] {
()=>validate1(arg, errors),
()=>validate2(arg, other, errors),
()=>validate3(arg, other2, errors)
};
foreach (var v in validators)
v();
您可以为验证器定义一个通用接口,并为每个用例实现一个 class。
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();
}
好吧,我考虑以类似 Fluent 的风格实现验证:
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();
这样您就可以摆脱那些 lists/packs 到处都是的错误,并且只需将验证错误流重定向到您想要的任何其他验证器。此外,您始终可以在某个时候停止验证,方法是调用 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);
}
}
我有一个调用其他一些工具的验证方法:
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();
}
我想要一些方法来制作如下代码,使用 for 循环来调用每个验证器:
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();
}
我该怎么做?
你可以试试这个
var validators = new Action[] {
()=>validate1(arg, errors),
()=>validate2(arg, other, errors),
()=>validate3(arg, other2, errors)
};
foreach (var v in validators)
v();
您可以为验证器定义一个通用接口,并为每个用例实现一个 class。
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();
}
好吧,我考虑以类似 Fluent 的风格实现验证:
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();
这样您就可以摆脱那些 lists/packs 到处都是的错误,并且只需将验证错误流重定向到您想要的任何其他验证器。此外,您始终可以在某个时候停止验证,方法是调用 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);
}
}