You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Fluent Validation中通过自定义规则校验其他属性

问题描述

假设存在如下类:

public class MyClass
{
    public string Property1 { get; set; }  
    public string Property2 {get; set; }     
    public string Property3 { get; set; } 
} 

以及对应的验证器类:

public class MyClassValidator : AbstractValidator<MyClass>
{
    public MyClassValidator ()
    {
        RuleFor(myClass => myClass.Property1).Property1();
    }
}

当前已有Property1的自定义验证规则:

public static IRuleBuilderOptions<T, string>
    Property1<T>(this IRuleBuilder<T, string> ruleBuilder)
    {
        return ruleBuilder.NotNull()
                          .NotEmpty()
                          .Length(12);
    }

现希望修改该自定义规则,实现当Property2的值为"qwerty"时,校验Property1的值不能为"q",但原写法无法正确获取并使用Property2的值,同时希望该校验规则能复用在其他类中。

解决方案

1. 核心思路:用接口约束保证复用性,通过上下文获取父对象

要在Property1的校验规则里拿到Property2的值,得借助FluentValidation的Custom方法获取父对象上下文,同时通过泛型接口约束,确保只要类有Property2就能复用这个规则,避免写死依赖特定类。

2. 修改后的通用自定义规则

先定义一个接口,约束类必须包含Property2:

public interface IHasProperty2
{
    string Property2 { get; set; }
}

然后修改自定义扩展方法,加上泛型约束,同时新增条件校验逻辑:

public static IRuleBuilderOptions<T, string> Property1<T>(this IRuleBuilder<T, string> ruleBuilder)
    where T : IHasProperty2
{
    return ruleBuilder
        // 保留原有校验规则
        .NotNull()
        .NotEmpty()
        .Length(12)
        // 添加自定义条件校验
        .Custom((property1Value, context) =>
        {
            // 从上下文拿到当前校验的父对象实例
            var targetObj = (T)context.InstanceToValidate;
            
            // 判断触发条件:Property2是"qwerty"且Property1是"q"时,添加失败提示
            if (targetObj.Property2 == "qwerty" && property1Value == "q")
            {
                context.AddFailure("当Property2为qwerty时,Property1不能为q");
            }
        });
}

3. 让目标类实现接口即可复用规则

不管是原来的MyClass还是其他需要用这个规则的类,只要实现IHasProperty2接口就行:

// 原MyClass实现接口
public class MyClass : IHasProperty2
{
    public string Property1 { get; set; }  
    public string Property2 {get; set; }     
    public string Property3 { get; set; } 
}

// 其他类复用示例
public class AnotherClass : IHasProperty2
{
    public string Property1 { get; set; }
    public string Property2 { get; set; }
    // 其他自定义属性...
}

4. 验证器使用方式完全不变

不管哪个类的验证器,调用规则的方式和之前一样:

public class MyClassValidator : AbstractValidator<MyClass>
{
    public MyClassValidator()
    {
        RuleFor(x => x.Property1).Property1();
    }
}

public class AnotherClassValidator : AbstractValidator<AnotherClass>
{
    public AnotherClassValidator()
    {
        RuleFor(x => x.Property1).Property1();
    }
}

要点总结

  • 泛型约束where T : IHasProperty2保证了只有符合条件的类能使用规则,避免编译报错。
  • context.InstanceToValidate是获取父对象的关键,通过它能拿到当前校验对象的所有属性。
  • 原有校验逻辑完全保留,只新增了条件校验,实现了增量修改。

内容的提问来源于stack exchange,提问作者Aleksey K

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 02:55:19