上一篇 2) 验证器实现 简单描述了下验证器的简单实现
本文将说说Fluent方式的实现,欢迎大神们指点指点
3) Fluent以及扩展方法实现
我们按照之前 Fluent 的设想以及我们解耦的方式,所以我们先实现一个创建验证器创建者的静态类:
public static class ValIDation{ public static IValIDatorBuilder<T> NewValIDatorBuilder<T>() // 创建验证器创建者 { return Container.Resolve<IValIDatorBuilder<T>>(); } public static ValIDateContext CreateContext(object valIDateObject,ValIDateOption option = ValIDateOption.StopOnFirstFailure,params string[] ruleSetList) // 创建验证数据上下文参数 { var result = Container.Resolve<ValIDateContext>(); result.Option = option; result.RuleSetList = ruleSetList; result.ValIDateObject = valIDateObject; return result; }}
我们接着实现 IValIDatorBuilder
public class ValIDatorBuilder<T> : IValIDatorBuilder<T>{ public ObservableCollection<IValIDateRuleBuilder> Builders { get; set; } public ValIDatorBuilder() { Builders = new ObservableCollection<IValIDateRuleBuilder>(); } public IValIDator Build() // 最终build 方法 { var result = Container.Resolve<IValIDatorSetter>(); result.SetRules(Builders.Select(i => i.Build())); return result; } public IFluentRuleBuilder<T,TProperty> RuleFor<TProperty>(Expression<Func<T,TProperty>> Expression) // 验证规则创建者方法 { ParamHelper.CheckParamNull(Expression,"Expression","Can't be null"); var builder = Container.Resolve<IRuleBuilder<T,TProperty>>(); builder.SetValueGetter(Expression); Builders.Add(builder as IValIDateRuleBuilder); return builder; } public voID RuleSet(string ruleSet,Action<IValIDatorBuilder<T>> 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<IValIDateRuleBuilder>((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<Student>(); // 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<T,TValue> : IRuleBuilder<T,TValue>{ public string RuleSet { get; set; } public Func<object,TValue> ValueGetter { get; protected set; } public Expression<Func<T,TValue>> ValueExpression { get; protected set; } public string Valuename { get; set; } public string Error { get; set; } public IValIDateRuleBuilder NextRuleBuilder { get; set; } public Func<ValIDateContext,bool> Condition { get; set; } public Func<ValIDateContext,string,IValIDateResult> ValIDateFunc { get; set; } public voID SetValueGetter(Expression<Func<T,TValue>> Expression) // 设置获取值的方法 { ValueExpression = Expression; var stack = new Stack<MemberInfo>(); var memberExp = Expression.Body as MemberExpression; while (memberExp != null) { stack.Push(memberExp.Member); memberExp = memberExp.Expression as MemberExpression; } var p = Expression.Parameter(typeof(object),"p"); var convert = Expression.Convert(p,typeof(T)); Expression exp = convert; if (stack.Count > 0) { while (stack.Count > 0) { exp = Expression.MakeMemberAccess(exp,stack.Pop()); } Valuename = exp.ToString().Replace(convert.ToString() + ".",""); // 设置默认的属性名 } else { Valuename = string.Empty; } ValueGetter = Expression.Lambda<Func<object,TValue>>(exp,p).Compile(); // 用表达式生成动态获取不同对象的值的方法 } public IFluentRuleBuilder<T,TProperty> ThenRuleFor<TProperty>(Expression<Func<T,TProperty>> Expression) // 创建子级规则接口方法 { var builder = Utils.RuleFor(Expression); NextRuleBuilder = builder as IValIDateRuleBuilder; return builder; } public IValIDateRule Build() // 规则创建方法 { var rule = Container.Resolve<IValIDateRule>(); rule.Valuename = Valuename; rule.Error = Error; rule.ValIDateFunc = ValIDateFunc; rule.Condition = Condition; rule.RuleSet = RuleSet; var nextBuilder = NextRuleBuilder; if (nextBuilder != null) rule.NextRule = nextBuilder.Build(); return rule; }}
貌似我们完成了大部分了,但是好像哪里不对,
回忆一下,好像这个持有如何验证逻辑方法的属性没有相关代码处理
public class ValIDateRule : IValIDateRule{ public Func<ValIDateContext,IValIDateResult> ValIDateFunc { get; set; }}
好吧,我们来建立一个基类先:
public abstract class BaseChecker<T,TProperty>{ public virtual IRuleMessageBuilder<T,TProperty> SetValIDate(IFluentRuleBuilder<T,TProperty> builder) // 设置验证规则逻辑方法 { ParamHelper.CheckParamNull(builder,"builder","Can't be null"); var build = builder as IRuleBuilder<T,TProperty>; build.ValIDateFunc = (context,name,error) => { var value = build.ValueGetter(context.ValIDateObject); var result = Container.Resolve<IValIDateResult>(); return ValIDate(result,value,error); }; return build as IRuleMessageBuilder<T,TProperty>; } public IValIDateResult GetResult() // 获取验证结果实例对象 { return Container.Resolve<IValIDateResult>(); } 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 error); // 验证规则逻辑接口}
再接着我们实现一个Must check 类:
public class MustChecker<T,TProperty> : BaseChecker<T,TProperty>{ private Func<TProperty,bool> m_MustBeTrue; public MustChecker(Func<TProperty,bool> func) { ParamHelper.CheckParamNull(func,"func","Can't be null"); m_MustBeTrue = func; } public overrIDe IValIDateResult ValIDate(IValIDateResult result,string error) { if (!m_MustBeTrue(value)) { AddFailure(result,error); } return result; }}
然后我们接口绑定加上:
public static class Container{ public static IlifetimeScope CurrentScope { get; set; } public static voID Init(Action<ContainerBuilder> action) { ParamHelper.CheckParamNull(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.RegisterGeneric(typeof(RuleBuilder<,>)).As(typeof(IRuleBuilder<,>)).InstancePerDependency(); builder.Register(c => new ValIDateContext() { RuleSelector = c.Resolve<IRuleSelector>() }); builder.RegisterType<ValIDateRule>().As<IValIDateRule>().InstancePerDependency(); builder.RegisterType<ValIDateResult>().As<IValIDateResult>().InstancePerDependency(); builder.RegisterGeneric(typeof(ValIDatorBuilder<>)).As(typeof(IValIDatorBuilder<>)).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>(); }}
再然后我们添加 must 的扩展方法:
public static class Syntax{ public static IRuleMessageBuilder<T,TProperty> Must<T,TProperty>(this IFluentRuleBuilder<T,TProperty> builder,Func<TProperty,bool> func) { return new MustChecker<T,TProperty>(func).SetValIDate(builder); }}
我们再添加一些消息设置相关的扩展方法:
public static class Syntax{ .... public static IRuleMessageBuilder<T,TProperty> When<T,TProperty>(this IRuleMessageBuilder<T,"Can't be null"); var ruleBuilder = builder as IRuleBuilder<T,TProperty>; ruleBuilder.Condition = (context) => { var value = ruleBuilder.ValueGetter(context.ValIDateObject); return func(value); }; return builder; } public static IRuleMessageBuilder<T,TProperty> OverrIDename<T,string name) { (builder as IValIDateRuleBuilder).Valuename = name; return builder; } public static IRuleMessageBuilder<T,TProperty> OverrIDeError<T,string error) { (builder as IValIDateRuleBuilder).Error = error; return builder; }}
大功告成,我们现在就可以这样使用了:
Container.Init();var builder = ValIDation.NewValIDatorBuilder<Student>();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: 大神们快快给我些批评吧,冰天雪地跪求了
总结以上是内存溢出为你收集整理的实现一个对象验证库系列 -- 3) Fluent以及扩展方法实现 (请大神批评)全部内容,希望文章能够帮你解决实现一个对象验证库系列 -- 3) Fluent以及扩展方法实现 (请大神批评)所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)