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

如何从RuleBuilderOptions获取PropertyValidatorContext实现自定义When扩展

解决FluentValidation自定义When扩展获取上下文的问题

嘿,我懂你想实现的功能——给FluentValidation加个自定义的WhenHasChanged扩展,只在实体属性确实发生变更时才执行后续验证规则对吧?你现在的问题在于,试图在规则构建阶段从IRuleBuilderOptions里拿PropertyValidatorContext,但这个上下文只有在实际验证执行阶段才会存在,所以直接从rule对象里是拿不到的。

正确的实现思路

FluentValidation的When方法本身就支持接收一个包含PropertyValidatorContext的委托,这个委托会在验证执行时被调用,这时候你就能拿到当前的实例和属性名了。我们可以基于这个重载来封装你的逻辑:

public static IRuleBuilderOptions<T, TProperty> WhenHasChanged<T, TProperty>(this IRuleBuilderOptions<T, TProperty> rule)
{
    return rule.When(context => 
    {
        // 将实例转换为你的变更跟踪接口
        var changeTrackingInstance = context.Instance as IChangeTrackingObject;
        if (changeTrackingInstance == null)
        {
            // 如果实例不支持变更跟踪,默认跳过验证(可根据需求调整)
            return false;
        }

        // 检查当前属性是否在变更列表中
        if (!changeTrackingInstance.GetChangedProperties().TryGetValue(context.PropertyName, out var propertyChange))
        {
            // 属性未发生变更,跳过后续验证
            return false;
        }

        // 比较新旧值,只有当值确实变化时才执行验证
        var oldValue = propertyChange.OldValue;
        var newValue = context.PropertyValue;
        return oldValue == null ? newValue != null : !oldValue.Equals(newValue);
    });
}

关键说明

  • 规则构建 vs 验证执行:IRuleBuilderOptions是用来配置验证规则的对象,在你写RuleFor(x => x.Name).WhenHasChanged()的时候就存在了,但这时候还没有要验证的实例和上下文。只有当调用Validate方法验证实体时,才会创建PropertyValidatorContext并传入When的委托。
  • When的逻辑:When的委托返回true时,后续的验证规则才会执行;返回false时,规则会被跳过。上面的代码逻辑是:只有当属性确实被修改(新旧值不同)时,才触发验证。
  • 异常处理:代码里考虑了IChangeTrackingObject转换失败的情况,你可以根据自己的业务需求调整这部分逻辑(比如抛出异常或者默认执行验证)。

使用示例

之后你就可以像这样使用这个扩展:

RuleFor(x => x.Email)
    .WhenHasChanged()
    .NotEmpty()
    .EmailAddress();

这段代码会只在Email属性发生变更时,才检查它是否为空和是否符合邮箱格式。

内容的提问来源于stack exchange,提问作者johnny 5

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:00:45