Implement an object verification Library series and verification Library Series

Source: Internet
Author: User

Implement an object verification Library series and verification Library Series
Past Situation Review:

Previous Article 2) the validator implementation briefly describes the simple implementation of the validator

This article will talk about the implementation of the Fluent method.

 

3) Fluent and extension method implementation

We follow the idea of Fluent and the decoupling method, so we first implement a static class for creating the creator of the validators:

Public static class Validation {public static IValidatorBuilder <T> NewValidatorBuilder <T> () // create the validator creator {return Container. resolve <IValidatorBuilder <T> ();} public static ValidateContext CreateContext (object validateObject, ValidateOption option = ValidateOption. stopOnFirstFailure, params string [] ruleSetList) // create the verification data context parameter {var result = Container. resolve <ValidateContext> (); result. option = option; result. ruleSetList = ruleSetList; result. validateObject = validateObject; return result ;}}

 

We then implement IValidatorBuilder

Public class ValidatorBuilder <T>: IValidatorBuilder <T> {public ObservableCollection <IValidateRuleBuilder> Builders {get; set;} public ValidatorBuilder () {Builders = new ObservableCollection <IValidateRuleBuilder> ();} public IValidator Build () // final build method {var result = Container. resolve <IValidatorSetter> (); result. setRules (Builders. select (I => I. build (); return result;} public IFluentRuleBuilder <T, TPr Operty> RuleFor <TProperty> (Expression <Func <T, TProperty> expression) // verify the rule creator method {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) // rule group flag setting method {P AramHelper. 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! = Policycollectionchangedaction. add) return; foreach (var item in e. newItems) {item. ruleSet = upRuleSet ;}}); Builders. collectionChanged + = updateRuleSet; action (this); Builders. collectionChanged-= updateRuleSet;} // The Rule grouping flag setting method simplifies the setting format and makes the code clearer. // For example, // 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 ");//});}

  

Then we implement 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> Condi Tion {get; set;} public Func <ValidateContext, string, string, IValidateResult> ValidateFunc {get; set;} public void SetValueGetter (Expression <Func <T, TValue> expression) // set the method for obtaining the value {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 () + ". "," "); // set the default attribute name} else {ValueNa Me = string. empty;} ValueGetter = Expression. lambda <Func <object, TValue> (exp, p ). compile (); // method for generating dynamic values for different objects using expressions} public IFluentRuleBuilder <T, TProperty> ThenRuleFor <TProperty> (Expression <Func <T, TProperty> expression) // create sub-level Rule interface method {var builder = Utils. ruleFor (expression); NextRuleBuilder = builder as IValidateRuleBuilder; return builder;} public IValidateRule Build () // rule creation method {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 ;}}

  

It seems that we have completed most of the work, but it seems that something is wrong,

Recall that there is no code to process this property holding the logic method for verification.

public class ValidateRule : IValidateRule{public Func<ValidateContext, string, string, IValidateResult> ValidateFunc { get; set; }}

Okay, let's create a base class first:

Public abstract class BaseChecker <T, TProperty> {public virtual IRuleMessageBuilder <T, TProperty> SetValidate (IFluentRuleBuilder <T, TProperty> builder) // sets the logic method of the verification rule {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, name, error) ;}; return build as IRuleMessageBuilder <T, TProperty >;} public IValidateResult GetResult () // obtain the verification result instance object {return Container. resolve <IValidateResult> ();} public void AddFailure (IValidateResult result, string name, object value, string error) // Add error message {result. failures. add (new ValidateFailure () {Name = name, Value = value, Error = error});} public abstract IValidateResult Validate (IValidateResult result, TProperty value, string name, string error ); // verify the logic interface of the Rule}

  

Then we implement an Must check class:

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, TProperty value, string name, string error){if (!m_MustBeTrue(value)){AddFailure(result, name, value, error);}return result;}}

  

Then we add the following to the interface binding:

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.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>();}}

  

Then we add the must extension method:

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);}}

  

Let's add some extension methods related to message settings:

public static class Syntax{....public static IRuleMessageBuilder<T, TProperty> When<T, TProperty>(this IRuleMessageBuilder<T, TProperty> builder, Func<TProperty, bool> func){ParamHelper.CheckParamNull(func, "func", "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, TProperty>(this IRuleMessageBuilder<T, TProperty> builder, string name){(builder as IValidateRuleBuilder).ValueName = name;return builder;}public static IRuleMessageBuilder<T, TProperty> OverrideError<T, TProperty>(this IRuleMessageBuilder<T, TProperty> builder, string error){(builder as IValidateRuleBuilder).Error = error;return builder;}}

  

We can use the following code now:

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);

  

The final code and dll can be obtained through the following method:

Nuget:Https://www.nuget.org/packages/ObjectValidator/

Github:Https://github.com/fs7744/ObjectValidator

 

PS: Let's give me some criticism.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.