前情回顾:
上一篇 2) 验证器实现 简单描述了下验证器的简单实现
本文将说说Fluent方式的实现,欢迎大神们指点指点
3) Fluent以及扩展方法实现
我们按照之前 Fluent 的设想以及我们解耦的方式,所以我们先实现一个创建验证器创建者的静态类:
public static class Validation { public static IValidatorBuilderNewValidatorBuilder () // 创建验证器创建者 { return Container.Resolve >(); } public static ValidateContext CreateContext(object validateObject, ValidateOption option = ValidateOption.StopOnFirstFailure, params string[] ruleSetList) // 创建验证数据上下文参数 { var result = Container.Resolve (); result.Option = option; result.RuleSetList = ruleSetList; result.ValidateObject = validateObject; return result; } }
我们接着实现 IValidatorBuilder
public class ValidatorBuilder: IValidatorBuilder { public ObservableCollection Builders { get; set; } public ValidatorBuilder() { Builders = new ObservableCollection (); } public IValidator Build() // 最终build 方法 { var result = Container.Resolve (); result.SetRules(Builders.Select(i => i.Build())); return result; } public IFluentRuleBuilder RuleFor (Expression > expression) // 验证规则创建者方法 { ParamHelper.CheckParamNull(expression, "expression", "Can't be null"); var builder = Container.Resolve >(); builder.SetValueGetter(expression); Builders.Add(builder as IValidateRuleBuilder); return builder; } public void RuleSet(string ruleSet, Action > action) // 规则分组标志设置方法 { ParamHelper.CheckParamEmptyOrNull(ruleSet, "ruleSet", "Can't be null"); ParamHelper.CheckParamNull(action, "action", "Can't be null"); var upRuleSet = ruleSet.ToUpper(); var updateRuleSet = new NotifyCollectionChangedEventHandler ((o, e) => { if (e.Action != NotifyCollectionChangedAction.Add) return; foreach (var item in e.NewItems) { item.RuleSet = upRuleSet; } }); Builders.CollectionChanged += updateRuleSet; action(this); Builders.CollectionChanged -= updateRuleSet; } // 规则分组标志设置方法这样实现可以简化设置的格式,让代码更清晰 // 比如 // var builder = Validation.NewValidatorBuilder (); // builder.RuleSet("A", b => // { // b.RuleFor(i => i.Name).NotNull() // .Must(i=>i.Length > 10) // .OverrideName("student name") // .OverrideError("no name") // .ThenRuleFor(i => i.Age) // .Must(i => i >= 0 && i <= 18) // .OverrideName("student age") // .OverrideError("not student"); // }); }
接着我们实现 IRuleBuilder:
public class RuleBuilder: IRuleBuilder { public string RuleSet { get; set; } public Func
貌似我们完成了大部分了,但是好像哪里不对,
回忆一下,好像这个持有如何验证逻辑方法的属性没有相关代码处理
public class ValidateRule : IValidateRule { public FuncValidateFunc { get; set; } }
好吧,我们来建立一个基类先:
public abstract class BaseChecker{ public virtual IRuleMessageBuilder SetValidate(IFluentRuleBuilder builder) // 设置验证规则逻辑方法 { ParamHelper.CheckParamNull(builder, "builder", "Can't be null"); var build = builder as IRuleBuilder ; build.ValidateFunc = (context, name, error) => { var value = build.ValueGetter(context.ValidateObject); var result = Container.Resolve (); return Validate(result, value, name, error); }; return build as IRuleMessageBuilder ; } public IValidateResult GetResult() // 获取验证结果实例对象 { return Container.Resolve (); } public void AddFailure(IValidateResult result, string name, object value, string error) // 添加错误信息 { result.Failures.Add(new ValidateFailure() { Name = name, Value = value, Error = error }); } public abstract IValidateResult Validate(IValidateResult result, TProperty value, string name, string error); // 验证规则逻辑接口 }
再接着我们实现一个Must check 类:
public class MustChecker: BaseChecker { private Func m_MustBeTrue; public MustChecker(Func func) { ParamHelper.CheckParamNull(func, "func", "Can't be null"); m_MustBeTrue = func; } public override IValidateResult Validate(IValidateResult result, TProperty value, string name, string error) { if (!m_MustBeTrue(value)) { AddFailure(result, name, value, error); } return result; } }
然后我们接口绑定加上:
public static class Container { public static ILifetimeScope CurrentScope { get; set; } public static void Init(Actionaction) { 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 ().As ().SingleInstance(); builder.RegisterGeneric(typeof(RuleBuilder<,>)).As(typeof(IRuleBuilder<,>)).InstancePerDependency(); builder.Register(c => new ValidateContext() { RuleSelector = c.Resolve () }); builder.RegisterType ().As ().InstancePerDependency(); builder.RegisterType ().As ().InstancePerDependency(); builder.RegisterGeneric(typeof(ValidatorBuilder<>)).As(typeof(IValidatorBuilder<>)).InstancePerDependency(); builder.RegisterType ().As ().InstancePerDependency(); }); } public static void Clear() { var scope = CurrentScope; if (scope != null) scope.Dispose(); } public static T Resolve () { return CurrentScope.Resolve (); } }
再然后我们添加 must 的扩展方法:
public static class Syntax { public static IRuleMessageBuilderMust (this IFluentRuleBuilder builder, Func func) { return new MustChecker (func).SetValidate(builder); } }
我们再添加一些消息设置相关的扩展方法:
public static class Syntax { .... public static IRuleMessageBuilderWhen (this IRuleMessageBuilder builder, Func func) { ParamHelper.CheckParamNull(func, "func", "Can't be null"); var ruleBuilder = builder as IRuleBuilder ; ruleBuilder.Condition = (context) => { var value = ruleBuilder.ValueGetter(context.ValidateObject); return func(value); }; return builder; } public static IRuleMessageBuilder OverrideName (this IRuleMessageBuilder builder, string name) { (builder as IValidateRuleBuilder).ValueName = name; return builder; } public static IRuleMessageBuilder OverrideError (this IRuleMessageBuilder builder, string error) { (builder as IValidateRuleBuilder).Error = error; return builder; } }
大功告成,我们现在就可以这样使用了:
Container.Init(); var builder = Validation.NewValidatorBuilder(); builder.RuleSet("A", b => { b.RuleFor(i => i.Name).Must(i=>i.Length > 10) .OverrideName("student name") .OverrideError("no name") .ThenRuleFor(i => i.Age) .Must(i => i >= 0 && i <= 18) .OverrideName("student age") .OverrideError("not student"); }); var v = builder.Build(); var student = new BigStudent() { Age = 13, Name = "v" }; var context = Validation.CreateContext(student); var result = v.Validate(context); Assert.IsNotNull(result); Assert.True(result.IsValid); Assert.True(result.Failures.Count == 0);
最后代码和dll可以通过如下方法获取:
nuget:https://www.nuget.org/packages/ObjectValidator/
github:https://github.com/fs7744/ObjectValidator
PS: 大神们快快给我些批评吧,冰天雪地跪求了