优化Fluent Validation代码:将重复代码转为单个扩展方法
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
IAdditionalrules across multiple validators. - Easier maintenance: If you need to update the validation logic for
IdorVersion, 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

