【问题标题】:FluentValidation SetCollectionValidator for derived typesFluentValidation SetCollectionValidator 派生类型
【发布时间】:2014-09-16 20:38:57
【问题描述】:

如何在派生类型的集合项上设置验证器?

class BaseClass
{

}

class DerivedClass : BaseClass
{

}

class SomeClass
{
    public IEnumerable<BaseClass> BaseClasses { get; set; }
}

class DerivedClassValidator : AbstractValidator<DerivedClass>
{

}

class SomeClassValidator : AbstractValidator<SomeClass>
{
    public SomeClassValidator()
    {
        RuleFor(x => x.BaseClasses).????.SetCollectionValidator(new DerivedClassValidator);
    }
}

只是想知道...

有没有办法将其转换为特定类型,例如

RuleFor(x => x.SomeCollection).CastTo(typeof(SomeDerivedType)).SetCollectionValidator(new SomeDerivedValidator());

【问题讨论】:

    标签: c# .net validation extension-methods fluentvalidation


    【解决方案1】:

    6年后:请看this link
    按照说明进行操作,底部显示:

    此方法也适用于集合,其中集合的每个元素可能是不同的子类。

    【讨论】:

      【解决方案2】:

      我想添加一些东西来帮助别人。我受到 Evgeny Levin 解决方案的启发。 我更喜欢分隔每个验证器,而不是 When 中的规则列表。

      public class CommonBaseClassValidator : AbstractValidator<BaseClass>
      {
          public CommonBaseClassValidator()
          {
              //All rules for shared properties
              RuleFor(x => x.Name)
                  .NotEmpty();
      
              RuleFor(x => x.Name)
                      .Length(0, 10);
      
              //special rules for derived types
              When(model => model.GetType() == typeof(DerivedClassOne), 
                  () => RuleFor(entity => entity as DerivedClassOne)
                          .SetValidator(new DerivedClassOneValidator()));
      
              When(model => model.GetType() == typeof(DerivedClassTwo), 
                  () => RuleFor(entity => entity as DerivedClassTwo)
                      .SetValidator(new DerivedClassTwoValidator()));
          }
      }
      

      希望对您有所帮助。

      【讨论】:

        【解决方案3】:

        我创建这个是为了让处理这个场景更简单:

        public class DerivedValidatorBase<TBase> : AbstractValidator<TBase>
        {
            public void MapDerivedValidator<TType, TValidatorType>()
                where TValidatorType : IEnumerable<IValidationRule>, IValidator<TType>, new()
                where TType: TBase
            {
                When(t => t.GetType() == typeof(TType), () => AddDerivedRules<TValidatorType>());
            }
        
            public void MapDerivedValidator<TType, TValidatorType>(TValidatorType validator)
                where TValidatorType : IEnumerable<IValidationRule>, IValidator<TType>
                where TType: TBase
            {
                When(t => t.GetType() == typeof(TType), () => AddDerivedRules<TValidatorType>(validator));
            }
        
            private void AddDerivedRules<T>(T validator)
                where T : IEnumerable<IValidationRule>
            {
                foreach (var rule in validator)
                {
                    this.AddRule(rule);
                }
            }
        
            private void AddDerivedRules<T>()
                where T : IEnumerable<IValidationRule>, new()
            {
                IEnumerable<IValidationRule> validator = new T();
                foreach (var rule in validator)
                {
                    this.AddRule(rule);
                }
            }
        }
        

        然后我简单地创建一个基本的验证器类:

        public class CommonBaseClassValidator : DerivedValidatorBase<BaseClass>
        {
            public CommonBaseClassValidator()
            {
                MapDerivedValidator<DerivedClass, DerivedClassValidator>();
            }
        }
        

        或者当使用依赖注入时:

        public class CommonBaseClassValidator : DerivedValidatorBase<BaseClass>
        {
            public CommonBaseClassValidator(DerivedClassValidator validator)
            {
                MapDerivedValidator<DerivedClass, DerivedClassValidator>(validator);
            }
        }
        

        使用中:

        RuleFor(v => v.BaseClasses).SetCollectionValidator(new CommonBaseClassValidator());
        

        这样我可以为派生类重复使用现有的验证器,我可能在别处使用这些验证器,并轻松映射它们。

        【讨论】:

          【解决方案4】:

          您可以使用规则的条件包装来验证集合,其中包含不同派生类型的对象。

          假设你有下一个类层次结构:

          public class BaseClass
          {
              public string Name { get; set; }
          }
          
          public class DerivedClassOne : BaseClass
          {
              public int Count { get; set; }
          }
          
          public class DerivedClassTwo : BaseClass
          {
              public double Price { get; set; }
          }
          

          以及带有BaseClass 对象集合的容器类:

          public class ContainerClass
          {
              public List<BaseClass> Collection { get; set; } 
          }
          

          主要思想是创建一个验证器类,负责所有类层次结构的验证:

          public class CommonBaseClassValidator : AbstractValidator<BaseClass>
          {
              public CommonBaseClassValidator()
              {
                  //common rule for all BaseClass types
                  RuleFor(x => x.Name)
                      .NotEmpty();
          
                  // special rules for base type
                  When(model => model.GetType() == typeof (BaseClass), () =>
                  {
                      RuleFor(x => x.Name)
                          .Length(0, 10);
                      // add rules here
                  });
          
                  //special rules for derived types
                  When(model => model.GetType() == typeof(DerivedClassOne), () =>
                  {
                      RuleFor(model => ((DerivedClassOne) model).Count)
                          .ExclusiveBetween(1, 9);
                      // add rules here
                  });
          
                  When(model => model.GetType() == typeof(DerivedClassTwo), () =>
                  {
                      RuleFor(model => ((DerivedClassTwo) model).Price)
                          .GreaterThan(1000);
                      // add rules here
                  });
              }
          }
          

          并将该类注册为集合项验证器:

          public class ContainerValidator : AbstractValidator<ContainerClass>
          {
              public ContainerValidator()
              {
                  RuleFor(model => model.Collection)
                      .SetCollectionValidator(new CommonBaseClassValidator());
              }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2012-10-23
            • 2019-03-02
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多