这个模式有点太抽象了。从某种意义上说,如果您从您想要做的事情开始,然后在此基础上进行抽象,那么您最终会得到更有用的概括。就像,在这种情况下,正在验证什么并不明显?某些 UI 中的用户输入?或者来自一些xml的数据?在第一种情况下,根据您的错误,您不仅需要一条错误消息,还可能需要一些更新 UI 的操作。然后验证抽象可能会采取完全不同的形式。实际代码从哪里来,进行验证?必须为每个验证规则实现特殊的类将产生一个糟糕的抽象,但当你真正想要使用它时,它会产生不必要的复杂代码。
另外,只有在绝对没有其他方法的情况下,我才会使用动态类型。
因此,假设您仍然感兴趣,下面的代码将用于验证引用类型。再说一次,如果您需要一个验证系统,您需要验证的值类型通常是某个类的属性,但请记住它不是通用的。
public class ValidationResult
{
public bool HasError { get; set; } = false;
public string ErrorText { get; set; } = "No error";
public void SetError(string errorMsg)
{
this.HasError = true;
ErrorText = errorMsg;
}
}
public interface IValidationRule
{
ValidationResult Validate();
}
public class ValidationRule<T> : IValidationRule
{
private Func<T, ValidationResult> validatorFunc;
private T validationSubject;
public ValidationRule(T validationSubject, Func<T, ValidationResult> validatorFunc)
{
this.validationSubject = validationSubject;
this.validatorFunc = validatorFunc;
}
public ValidationResult Validate() => validatorFunc?.Invoke(validationSubject);
}
public interface IValidator
{
void AddRule<T>(T validationSubject, Func<T, ValidationResult> validationFunc);
ValidationResult Validate();
}
public class Validator : IValidator
{
private readonly List<IValidationRule> rules = new List<IValidationRule>();
public void AddRule<T>(T validationSubject, Func<T,ValidationResult> validationFunc)
{
rules.Add(new ValidationRule<T>(validationSubject, validationFunc));
}
public ValidationResult Validate()
{
foreach (var rule in rules)
{
var result = rule.Validate();
if (result.HasError) return result;
}
return new ValidationResult();
}
}
要添加验证规则,您需要传入两个参数:稍后要验证的对象,以及包含逻辑并返回 ValidationResult 的 Func。像这样:
public class ValidatableObject
{
public int intValue;
}
private void Test()
{
var target = new ValidatableObject();
target.intValue = 1;
var validator = new Validator();
validator.AddRule(target, (x) =>
{
var validationResult = new ValidationResult();
if (x.intValue > 10) validationResult.SetError("Exceeds max value (10)");
return validationResult;
});
log(validator.Validate().ErrorText);
target.intValie = 100;
log(validator.Validate().ErrorText);
}