实现一个对象验证库系列 -- 2) 验证器实现 (请大神批评)
前情回顾:
上一篇 1) 接口介绍以及总体思路概述 简单描述了下库的设计思路
本文将说说验证器实现,欢迎大神指导更快更好的方案
2) 验证器实现
我们首先从用户调用的验证器开始实现,所以我们应该首先这样做
public class Validator : IValidator { public IValidateResult Validate(ValidateContext context) { } }
但是我们的验证器不是没有规则嘛?回忆一下我们好像是在为 Fluent 设计时添加了一个验证器设置规则的接口,所以我们应这样实现验证器:
public class Validator : IValidatorSetter { private List<IValidateRule> m_Rules = new List<IValidateRule>(); // 保存验证规则 public void SetRules(IEnumerable<IValidateRule> rules) { ParamHelper.CheckParamNull(rules, "rules", "Can't be null"); m_Rules.AddRange(rules); // 添加验证规则 } public IValidateResult Validate(ValidateContext context) { ParamHelper.CheckParamNull(context, "context", "Can't be null"); var list = context.RuleSetList; if (!list.IsEmptyOrNull()) { context.RuleSetList = list.Where(i => !string.IsNullOrEmpty(i)).Select(i => i.ToUpper()).ToArray(); } // 处理验证规则分组标志筛选列表 var rules = m_Rules.Where(i => context.RuleSelector.CanExecute(i, context)).ToArray(); // 筛选验证规则 var result = Container.Resolve<IValidateResult>(); if (!rules.IsEmptyOrNull()) { var tasks = rules.Select(i => Task.Factory.StartNew(() => i.Validate(context))).ToArray(); Task.WaitAll(tasks); // 执行验证 if (tasks.Any(i => i.IsFaulted)) { var exceptions = tasks.Where(i => i.IsFaulted) .Select(i => i.Exception); throw new AggregateException(exceptions); } // 处理task 的异常情况 var failures = tasks.Where(i => i.IsCompleted) .SelectMany(i => i.Result.Failures); result.Merge(failures); // 处理 验证结果 } return result; } }
接着我们再实现验证规则:
public class ValidateRule : IValidateRule { public IValidateRule NextRule { get; set; } public string RuleSet { get; set; } public string ValueName { get; set; } public string Error { get; set; } public Func<ValidateContext, bool> Condition { get; set; } public Func<ValidateContext, string, string, IValidateResult> ValidateFunc { get; set; } public IValidateResult Validate(ValidateContext context) { ParamHelper.CheckParamNull(ValidateFunc, "ValidateFunc", "Can't be null"); ParamHelper.CheckParamNull(context, "context", "Can't be null"); IValidateResult result = null; if (Condition == null || Condition(context)) // 判断用户的特殊过滤条件 { result = ValidateByFunc(context); // 执行规则的验证 } else { result = Container.Resolve<IValidateResult>(); } return result; } public IValidateResult ValidateByFunc(ValidateContext context) { IValidateResult result = ValidateFunc(context, ValueName, Error); //执行当前规则的验证逻辑 var nextRule = NextRule; if (nextRule != null && (result.IsValid || context.Option == ValidateOption.Continue)) // 判断是否有必要执行子级验证规则 { var nextResult = nextRule.Validate(context); // 执行子级验证规则 result.Merge(nextResult.Failures); // 处理子级验证结果 } return result; } }
等等,好像我们还没有实现验证规则分组标志筛选器,好吧,我们实现它吧
public class RuleSelector : IRuleSelector { public bool CanExecute(IValidateRule rule, ValidateContext context) { return string.IsNullOrEmpty(rule.RuleSet) || context.RuleSetList.IsEmptyOrNull() ? true : context.RuleSetList.Contains(rule.RuleSet); } }
我们把目前的实现与接口绑定到容器中:
public static class Container { public static ILifetimeScope CurrentScope { get; set; } public static void Init(Action<ContainerBuilder> action) { ParamHelper.CheckParamNull(action, "action", "Can't be null"); Clear(); var builder = new ContainerBuilder(); action(builder); var container = builder.Build(); CurrentScope = container.BeginLifetimeScope(); } public static void Init() { Init(builder => { // 绑定接口 builder.RegisterType<RuleSelector>().As<IRuleSelector>().SingleInstance(); builder.Register(c => new ValidateContext() { RuleSelector = c.Resolve<IRuleSelector>() }); builder.RegisterType<ValidateRule>().As<IValidateRule>().InstancePerDependency(); builder.RegisterType<ValidateResult>().As<IValidateResult>().InstancePerDependency(); builder.RegisterType<Validator>().As<IValidatorSetter>().InstancePerDependency(); }); } public static void Clear() { var scope = CurrentScope; if (scope != null) scope.Dispose(); } public static T Resolve<T>() { return CurrentScope.Resolve<T>(); } }
好吧,我们来简单试试吧:
Container.Init(); // 初始接口 var v = new Validator(); var rule = new ValidateRule() { ValidateFunc = (c, name, error) => { var f = new ValidateFailure() { Name = name, Error = error, Value = c }; return new ValidateResult(new List<ValidateFailure>() { f }); } }; v.SetRules(new List<ValidateRule>() { rule }); // 简单设置验证 var context = new ValidateContext() { RuleSelector = new RuleSelector() }; var result = v.Validate(context); // 试用一下 Assert.IsNotNull(result); Assert.True(result.IsValid); Assert.IsNotNull(result.Failures); Assert.AreEqual(0, result.Failures.Count);
好吧,没有实现 Fluent 设置验证规则的代码,现在整体看起来真丑啊
NEXT: 3) Fluent以及扩展方法实现