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)