Implement an Object validation library series--3) Fluent and the extension method implementation (please great God criticism)

Source: Internet
Author: User

Previously review:

Previous 2) Validator implementation Simple description of the next validator simple implementation

This article will talk about the realization of the fluent way, welcome the Great God to guide the guidance

3) Fluent and extended method implementation

We followed the previous Fluent idea and the way we decoupled, so we first implement a static class that creates the validator creator:

public static class Validation{public static ivalidatorbuilder<t> newvalidatorbuilder<t> ()  // Create Authenticator Creator {return container.resolve<ivalidatorbuilder<t>> ();} public static Validatecontext Createcontext (object validateobject,validateoption option = Validateoption.stoponfirstfailure, params string[] rulesetlist)  //create validation data context parameter {var result = container.resolve< Validatecontext> (); result. Option = Option;result. Rulesetlist = Rulesetlist;result. Validateobject = Validateobject;return result;}}

We go on to realize 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, Tproperty> rulefor<tproperty> (expression<func<t, TProperty>> expression)//validation 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 set method { 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;}    Rule grouping Flag setting method This implementation simplifies the format of the setup and makes the code clearer//such as//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> Condition {get; set;} Public Func<validatecontext, String, String, ivalidateresult> validatefunc {get; set;} public void Setvaluegetter (expression<func<t, tvalue>> Expression)//Set method to get 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 () + ".", ""); Sets the default property name}else{valuename = String. Empty;} Valuegetter = Expression.lambda<func<object, tvalue>> (exp, p). Compile (); Methods for generating dynamically obtained values of different objects using expressions}public ifluentrulebuilder<t, tproperty> thenrulefor<tproperty> (expression< Func<t, tproperty>> expression)//Create a child 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> (); 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 looks like we've done most of it, but it seems to be wrong.

Remember, it's like this property with how to validate a logical method has no related code handling

public class Validaterule:ivalidaterule{public Func<validatecontext, String, String, ivalidateresult> Validatefunc {get; set;}}

Well, let's build a base class first:

Public abstract class Basechecker<t, tproperty>{public virtual irulemessagebuilder<t, tproperty> Setvalidate (ifluentrulebuilder<t, tproperty> Builder)//Set validation rule logic method {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 ()//Get validation 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); Validation rule Logical Interface}

  

And then we implement a 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_mustb Etrue (value)) {addfailure (result, name, value, error);} return result;}}

  

Then we interface binding plus:

public static class Container{public static Ilifetimescope currentscope {get; set;} public static void Init (Action<containerbuilder> action) {Paramhelper.checkparamnull (Action, "Action", "Can ' t is 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> ();}}

  

And 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 more messages to set up the associated extension method:

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

  

It's done, we can use it 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 =, 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 in the following ways:

NuGet:https://www.nuget.org/packages/ObjectValidator/

GitHub:https://github.com/fs7744/ObjectValidator

PS: The gods, please give me some criticism, the ice and snow on their knees

Implement an Object validation library series--3) Fluent and the extension method implementation (please great God criticism)

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.