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

如何为匿名类型声明AbstractValidator以减少代码重复?

重构FluentValidation跨类型时间验证规则方案

匿名类型无法作为AbstractValidator<T>的泛型参数——因为匿名类型是编译器隐式生成的唯一类型,无法在代码中显式引用。因此需要换一种方式实现规则复用,以下是两种可行方案:

方案一:通过接口统一约束类型

1. 定义通用接口

先创建一个包含时间范围属性的接口,让所有需要该验证规则的类型实现它:

public interface IHasTimeRange
{
    DateTime Start { get; }
    DateTime End { get; }
}

让Meeting类实现该接口:

public class Meeting : IHasTimeRange
{
    public DateTime Start { get; set; }
    public DateTime End { get; set; }
    // 其他业务属性
}

2. 实现通用验证器

基于接口构建可复用的验证器:

internal sealed class TimeRangeValidator : AbstractValidator<IHasTimeRange>
{
    public TimeRangeValidator()
    {
        RuleFor(range => range)
            .Must(r => r.End > r.Start)
            .WithMessage("结束时间必须晚于开始时间");
    }
}

3. 扩展方法简化调用

创建扩展方法,让其他验证器可以快速复用规则:

public static class ValidationExtensions
{
    public static IRuleBuilderOptions<T, T> MustHaveValidTimeRange<T>(this IRuleBuilder<T, T> ruleBuilder)
        where T : IHasTimeRange
    {
        return ruleBuilder.SetValidator(new TimeRangeValidator());
    }
}

4. 在MeetingValidator中使用

internal sealed class MeetingValidator : AbstractValidator<Meeting>
{
    public MeetingValidator()
    {
        RuleFor(m => m)
            .MustHaveValidTimeRange();

        // 其他业务验证规则
    }
}

方案二:无需接口,用值元组+扩展方法封装

如果不想修改原有类型的结构,可以直接用值元组传递时间范围,把验证逻辑封装到扩展方法中:

public static class ValidationExtensions
{
    public static IRuleBuilderOptions<T, (DateTime Start, DateTime End)> MustHaveValidTimeRange<T>(
        this IRuleBuilder<T, (DateTime Start, DateTime End)> ruleBuilder)
    {
        return ruleBuilder
            .Must(range => range.End > range.Start)
            .WithMessage("结束时间必须晚于开始时间");
    }
}

在MeetingValidator中使用

internal sealed class MeetingValidator : AbstractValidator<Meeting>
{
    public MeetingValidator()
    {
        RuleFor(m => (m.Start, m.End))
            .MustHaveValidTimeRange();

        // 其他业务验证规则
    }
}

为什么不能用匿名类型?

匿名类型的类型名称由编译器自动生成,无法在代码中显式指定为泛型参数;且不同位置创建的匿名类型即使属性完全一致,也会被编译器视为不同类型,根本无法实现跨类型复用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 22:36:23