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

优化Fluent Validation代码:将重复代码转为单个扩展方法

Refactoring Fluent Validation: Extract Repetitive IAdditional Rules into Extension Methods

Got it, let's refactor that repetitive Fluent Validation code into clean, reusable extension methods—this will keep your validators DRY (Don't Repeat Yourself) and easier to maintain. Here's how to do it step by step:

Step 1: Create a Static Extension Class for Reusable Rules

First, we'll wrap all the validation logic specific to IAdditional into extension methods. This way, any validator that deals with a type implementing IAdditional can reuse these rules without duplicating code.

using FluentValidation;

public static class FluentValidationExtensions
{
    // Reusable rule for IAdditional.Id
    public static IRuleBuilderOptions<T, int> ValidateAdditionalId<T>(this IRuleBuilder<T, int> ruleBuilder)
    {
        return ruleBuilder
            .GreaterThan(0)
            .WithMessage("Additional ID must be a positive integer");
    }

    // Reusable rule for IAdditional.Version
    public static IRuleBuilderOptions<T, string> ValidateAdditionalVersion<T>(this IRuleBuilder<T, string> ruleBuilder)
    {
        return ruleBuilder
            .NotEmpty()
            .Matches(@"^[\w\d]+$")
            .WithMessage("Version must only contain letters, numbers, or underscores");
    }

    // Convenience method to apply ALL IAdditional rules at once
    public static void ApplyAdditionalValidationRules<T>(this AbstractValidator<T> validator)
        where T : class
    {
        validator.When(instance => instance is IAdditional, () =>
        {
            validator.RuleFor(instance => ((IAdditional)instance).Id)
                     .ValidateAdditionalId();
            
            validator.RuleFor(instance => ((IAdditional)instance).Version)
                     .ValidateAdditionalVersion();
        });
    }
}

Step 2: Simplify Your Original Validator

Now, you can replace that inline When block in your UserValidator with a single call to our extension method. This cleans up the validator and makes its intent clearer.

internal class UserValidator : AbstractValidator<IUser>
{
    public UserValidator()
    {
        // General IUser validation rules
        RuleFor(u => u.Name)
            .NotEmpty()
            .MaximumLength(50)
            .WithMessage("User name cannot be empty and must be under 50 characters");

        // Apply all IAdditional rules with one line
        this.ApplyAdditionalValidationRules();
    }
}

Step 3: Reuse the Extension in Other Validators

If you have other DTOs that implement IAdditional (like a hypothetical UpdateProduct), their validators can reuse the same extension method effortlessly:

internal class ProductValidator : AbstractValidator<IProduct>
{
    public ProductValidator()
    {
        // General IProduct rules
        RuleFor(p => p.Sku).NotEmpty().Length(6, 10);

        // Reuse the same IAdditional rules
        this.ApplyAdditionalValidationRules();
    }
}

Key Benefits

  • Reduced duplication: No more copying and pasting the same IAdditional rules across multiple validators.
  • Easier maintenance: If you need to update the validation logic for Id or Version, you only change it once in the extension class.
  • Cleaner code: Validators focus on their specific type's rules, while cross-cutting rules are handled in a single place.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 11:46:24