委托验证模式中未使用参数的优化方案咨询
基于委托的验证模式优化方案
问题背景
我实现了一套基于委托的验证模式,核心验证方法签名如下:
public bool IsPropertyValid<TValue>( TValue value, Func<TValue, bool, string?, (bool IsValid, IEnumerable<string> ErrorMessages)> validationDelegate, bool mandatory, string? errorSuffix = null) { // Validate using the delegate var (isValid, errorMessages) = validationDelegate?.Invoke(value, mandatory, errorSuffix) ?? (true, Enumerable.Empty<string>()); // do stuff }
同时编写了多个符合该委托签名的验证方法,例如:
public static (bool IsValid, IEnumerable<string> ErrorMessages) ValidateTextOnly(string value, bool mandatory, string? msgSuffix = null) { return ValidationMethods.IsTextOnly(value, mandatory) ? (true, Enumerable.Empty<string>()) : (false, new[] { ErrorMessage("must be letters only", msgSuffix, mandatory) }); } public static (bool IsValid, IEnumerable<string> ErrorMessages) ValidatePostalCode(string value, bool mandatory, string? msgSuffix = null) { return ValidationMethods.IsPostalCode(value, mandatory) ? (true, Enumerable.Empty<string>()) : (false, new[] { ErrorMessage("must be a valid postal code", msgSuffix, mandatory) }); }
错误信息由ErrorMessage方法生成:
private static string ErrorMessage(string? message, string? msgSuffix, bool mandatory) { message = string.Join(mandatory ? " and " : " or ", new [] { mandatory ? IsRequired : NotRequired, message } .Where(x => !string.IsNullOrEmpty(x))); return string.Join(" ", new[] { message, msgSuffix } .Where(x => !string.IsNullOrEmpty(x))); }
但ValidateEmpty方法并不需要mandatory参数,目前仅为匹配委托签名保留该参数,写法不够优雅:
public static (bool IsValid, IEnumerable<string> ErrorMessages) ValidateEmpty(string value, bool mandatory, string? msgSuffix = null) { return string.IsNullOrEmpty(value) ? (true, Enumerable.Empty<string>()) : (false, new[] { ErrorMessage(null, msgSuffix, false) }); }
曾考虑拆分验证方法(如ValidateText和ValidateTextMandatory)或设置mandatory为可空类型,但均不理想,希望找到更优的实现方式处理未使用参数的问题。
优化方案
1. 使用参数弃元(最简改动)
C# 7.0及以上支持参数弃元(_),用它替代未使用的mandatory参数,明确表示该参数不需要被使用,既符合委托签名,又让代码意图更清晰:
public static (bool IsValid, IEnumerable<string> ErrorMessages) ValidateEmpty(string value, bool _, string? msgSuffix = null) { return string.IsNullOrEmpty(value) ? (true, Enumerable.Empty<string>()) : (false, new[] { ErrorMessage(null, msgSuffix, false) }); }
这种方式零侵入,不需要修改委托签名或其他逻辑,仅调整当前方法的参数名,是最轻量化的解决方案。
2. 封装适配层(隔离核心逻辑)
如果希望核心验证方法完全不依赖无关参数,可以先定义一个不带mandatory的核心方法,再写一个适配器方法适配现有委托签名:
// 核心验证逻辑,无冗余参数 private static (bool IsValid, IEnumerable<string> ErrorMessages) ValidateEmptyCore(string value, string? msgSuffix = null) { return string.IsNullOrEmpty(value) ? (true, Enumerable.Empty<string>()) : (false, new[] { ErrorMessage(null, msgSuffix, false) }); } // 适配委托签名的包装方法 public static (bool IsValid, IEnumerable<string> ErrorMessages) ValidateEmpty(string value, bool _, string? msgSuffix = null) { return ValidateEmptyCore(value, msgSuffix); }
这种方式将核心逻辑与委托适配分离,后续如果委托签名变化,只需修改适配器即可,核心逻辑保持纯净。
3. 重构委托体系(长期扩展性)
如果后续会出现更多不同参数需求的验证方法,可以考虑重构委托体系,引入接口抽象:
// 定义基础验证接口 public interface IValidator<T> { (bool IsValid, IEnumerable<string> ErrorMessages) Validate(T value, string? errorSuffix = null); } // 支持必填性的扩展接口 public interface IMandatoryValidator<T> : IValidator<T> { (bool IsValid, IEnumerable<string> ErrorMessages) Validate(T value, bool mandatory, string? errorSuffix = null); } // 修改核心验证方法,接受接口实例 public bool IsPropertyValid<TValue>( TValue value, IValidator<TValue> validator, bool mandatory, string? errorSuffix = null) { var (isValid, errorMessages) = validator switch { IMandatoryValidator<TValue> mandatoryValidator => mandatoryValidator.Validate(value, mandatory, errorSuffix), _ => validator.Validate(value, errorSuffix) }; // do stuff }
然后针对不同验证场景实现对应的接口:
// ValidateEmpty实现基础接口,无需处理mandatory public class EmptyValidator : IValidator<string> { public (bool IsValid, IEnumerable<string> ErrorMessages) Validate(string value, string? errorSuffix = null) { return string.IsNullOrEmpty(value) ? (true, Enumerable.Empty<string>()) : (false, new[] { ErrorMessage(null, errorSuffix, false) }); } } // ValidateTextOnly实现扩展接口,支持mandatory public class TextOnlyValidator : IMandatoryValidator<string> { public (bool IsValid, IEnumerable<string> ErrorMessages) Validate(string value, bool mandatory, string? errorSuffix = null) { return ValidationMethods.IsTextOnly(value, mandatory) ? (true, Enumerable.Empty<string>()) : (false, new[] { ErrorMessage("must be letters only", errorSuffix, mandatory) }); } public (bool IsValid, IEnumerable<string> ErrorMessages) Validate(string value, string? errorSuffix = null) { // 可选:提供默认mandatory值的实现 return Validate(value, true, errorSuffix); } }
这种方式虽然改动较大,但扩展性更强,能更好应对后续复杂的验证需求,适合中大型项目。
内容的提问来源于stack exchange,提问作者spiral
相关产品推荐
相关产品推荐

