【问题标题】:C# delegate with params带参数的 C# 委托
【发布时间】:2017-09-04 08:46:05
【问题描述】:

我有一个调用其他工具的验证方法:

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

我该怎么做?

【问题讨论】:

  • 什么是otherother2validate 有 2 个重载吗?
  • 使用数组或 lambda 列表。如果您以前没有使用过 Microsoft 的在线文档,您可以放心使用。
  • @Sweeper 没有重载,它是三种不同的方法,它们有不同的参数列表。

标签: c# delegates action


【解决方案1】:

你可以试试这个

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

foreach (var v in  validators)
    v();

【讨论】:

    【解决方案2】:

    您可以为验证器定义一个通用接口并为每个用例实现一个类。

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

    【讨论】:

      【解决方案3】:

      好吧,我考虑以类似 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();
      

      通过这种方式,您将摆脱那些到处出现的错误列表/错误包,只需将验证错误流重定向到您想要的任何其他验证器。此外,您始终可以通过调用yield break 在某个时候停止验证,并且能够从它们创建ansamble。

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          猜你喜欢
          • 2010-12-25
          • 1970-01-01
          • 1970-01-01
          • 2014-12-10
          • 2013-01-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-11-17
          相关资源
          最近更新 更多