C#流畅验证用于一组类的层次结构

83

我有一组数据类的层次结构。

public class Base
{
    // Fields to be validated
}

public class Derived1 : Base
{
    // More fields to be validated
}

public class Derived2 : Base
{
    // More fields to be validated
}

如何在使用FluentValidation框架时,验证Derived1和Derived2的正确方法而不会为Base类的字段重复编写规则?

3个回答

137
public class Derived2Validator : AbstractValidator<Derived2>
{
    public Derived2Validator()
    {
        Include(new BaseValidator());
        Include(new Derived1Validator());
        RuleFor(d => d.Derived1Name).NotNull();
    }
}

Derived2Validator不需要继承BaseValidatorDerived1Validator

使用Include方法将其他验证器的规则包含进来即可。


23
我会使用这种方法,因为它更倾向于组合而非继承,这是优秀开发者的黄金法则。 - Alexander Marek
1
Include(new Derived2Validator()); 不是必要的,是吗? - Eren Ersönmez
8
如果你包含Include(new Derived2Validator()),那么就会形成一个无限循环。 - jonmeyer
我觉得include非常有用,但是有没有什么简单的方法来测试它呢? 我想到的唯一方法是为验证器编写一个接口,在其中调用include方法返回实例。 - Quico Llinares Llorens

94

有一个可行的方法:

public class Base
{
    public string BaseName { get; set; } 
}

public class Derived1 : Base
{
    public string Derived1Name { get; set; }
}

public class BaseValidator<T> : AbstractValidator<T> where T : Base
{
    public BaseValidator()
    {
        RuleFor(b => b.BaseName).NotNull();
    }
}

public class Derived1Validator : BaseValidator<Derived1>
{
    public Derived1Validator()
    {
        RuleFor(d => d.Derived1Name).NotNull();
    }
}

首先创建基础验证器,让它接受通用类型参数并指定该通用类型必须是“base”类型。设置您基类的一般规则,然后继续。

对于任何验证基类子对象的验证器,将这些验证器从基础验证器中继承,其中T将是派生类类型。


3
谢谢您的回答! - Nikolay Nahimov
太完美了!像魔法一样好用!注意到在派生构造函数后面不需要添加:base()。最初,我认为如果不显式调用基类构造函数,它不会执行基类测试。但是它确实可以! - Rashmi Pandit
如果你没有构造函数,则不需要添加base(),因为它会自动存在。如果你有除默认空构造函数之外的其他构造函数,则必须使用所需的签名来使用base()。在验证类上...可能永远不需要添加任何其他不同的构造函数。 - Piotr Kula
正是我所需要的。非常感谢!它完美地运行着。 - Andrei Bazanov
2
如果我现在有一个 ICollection<Base>,我想要验证它怎么办? - julealgon
1
我注意到使用这种方法,验证工作在服务器端,但客户端的data属性不会被JQuery无侵入式验证渲染,所以我不得不使用Include方法。 - Rami A.

2

我尝试过使用Include()方法,但是由swagger在 .net core 中生成的模型没有显示任何更改,因此这并不符合我的期望结果。有效的方法是创建一个新的继承自基类的验证器类。

/// <summary>
/// Base Class for entity validator classes that specifies a base validator class
/// </summary>
/// <typeparam name="T">The Type being validated</typeparam>
/// <typeparam name="TBaseClass">The validater assigned to the base type of the type being validated</typeparam>
public abstract class BaseAbstractValidator<T, TBaseClass> : AbstractValidator<T>
    where TBaseClass : IEnumerable<IValidationRule>
{
    protected BaseAbstractValidator() => AppendRules<TBaseClass>();

    /// <summary>
    /// Add the set of validation rules
    /// </summary>
    /// <typeparam name="TValidationRule"></typeparam>
    private void AppendRules<TValidationRule>() where TValidationRule : IEnumerable<IValidationRule>
    {
        var rules = (IEnumerable<IValidationRule>)Activator.CreateInstance<TValidationRule>();
        foreach (var rule in rules)
        {
            AddRule(rule);
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接