Search code examples
c#fluentvalidation

AbstractValidator for Anonymous Type


internal sealed class MeetingValidator : AbstractValidator<Meeting> 
{
    public MeetingValidator()
    {
      RuleFor(m => new { m.Start, m.End })
        .Must(d => d.End - d.Start > 0)

      // Other Rules
    }
}

Is there a way to declare a AbstractValidator on an anonymous type ?

This is for refactoring purposes.

The test is common to other types than Meeting and I want to minimize the duplication of my code.

internal sealed class EndDateValidator : AbstractValidator<????> 
{
    public EndDateValidator ()
    {
      RuleFor(m => ????)
        .Must(d => d.End - d.Start > 0)
    }
}


public static IRuleBuilderOptions<T, ????> MustHaveAEndStartDate<T>(this IRuleBuilder<T,  ????> ruleBuilder)
{
    return ruleBuilder.SetValidator(new EndDateValidator());
}


internal sealed class MeetingValidator : AbstractValidator<Meeting> 
{
    public MeetingValidator()
    {
      RuleFor(m => new { m.Start, m.End }) // or something else
        .MustHaveValidEndDate()
    }
}

Solution

  • In case you can't refactor the source class(es) (here: Meeting), then you can use a (DateTime Start, DateTime End) ValueTuple instead of an anonymous type, defining the validator as inheriting from AbstractValidator<(DateTime Start, DateTime End)>.

    internal sealed class MeetingValidator : AbstractValidator<Meeting>
    {
        public MeetingValidator()
        {
            RuleFor<(DateTime, DateTime)>(o => new(o.Start, o.End))
                .MustHaveValidEndDate();
        }
    }
    
    internal sealed class EndDateValidator : AbstractValidator<(DateTime Start, DateTime End)>
    {
        public EndDateValidator()
        {
            RuleFor(o => o).Must(o => o.End > o.Start);
        }
    }
    
    public static class Extensions
    {
        public static IRuleBuilderOptions<T, (DateTime Start, DateTime End)> MustHaveValidEndDate<T>(
            this IRuleBuilder<T, (DateTime Start, DateTime End)> ruleBuilder
            )
        {
            return ruleBuilder.SetValidator(new EndDateValidator());
        }
    }