CommonLibrary之Validation(2)
上一篇,介绍了CommonLibrary的Validation验证模块的接口,类继承关系以及ValidatorFluent链式调用的实现,这里继续把例子从头看起,简单的,一看就明白的设计和实现就不做赘述了,说说我理解中的一些比较好的值得学习的观念或方法;首先看:
Validation.IsAlpha("123abc", false)
Validation.IsAlphaNumeric("123abc", false, errors, "")
Validation.AreEqual<T>(t1, t2);
Validation,ValidationExtensions,ValidationExtensionsAssertive,3个类文件中同使用static partial class Validation,作者把基本验证(Validation)实现保存错误的参数类IErrors的ValidationExtensions,实现IComparable<T>,用来做类型比较的ValidationExtensionsAssertive物理上分开放置,这个可以在我们平时的设计做参考,物理上的好的放置让我们逻辑更清楚,维护更方便,其实无所谓了,看自己的理解和实际的编码需求了。这块很简单,看看就明白了。
其实如果我们想在懒点,简单的验证我们可以用扩展方法实现,"123abc".IsNumericExp(),恩,一切都是现成的,还等什么呢?
1 2 3 | public static bool IsNumericExp( this string str) { return Regex.IsMatch(str, RegexPatterns.Numeric); } |
这里讲讲这个接口: IComparable<T>,定义由值类型或类实现的通用的比较方法,以为排序实例创建类型特定的比较方法,如果我们要使用Validation类中的的类型比较方法,那么首先得实现
IComparable<>泛型接口的public int CompareTo(T t)方法,在该方法中编写我们需要比较的东西,比如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | public class User:IComparable<User> { public string UserName { get ; set ; } public DateTime CreateDate { get ; set ; } public string Email { get ; set ; } public string MobilePhone { get ; set ; } #region IComparable<User> 成员 public int CompareTo(User other) { return this .UserName.CompareTo(other.UserName); } #endregion } //调用方法: var errors = new ValidationResults(); Validation.AreEqual<User>(user1, user2,errors, "" ); PrintErrors(errors); |
Lamda
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | //实现 public void Example3_Lamda() { var val = new Validator(valEvent => { int errCount = valEvent.Results.Count; Validation.IsEmail( "kishore@" , false , valEvent.Results, string .Empty); Validation.IsUrl( "http://www" , false , valEvent.Results, string .Empty); Validation.IsPhoneUS( "111-111-111" , false , valEvent.Results, string .Empty); return errCount == valEvent.Results.Count; }); PrintErrors(val.Validate()); } //其实很简单,看一下Validator的构造函数就清楚了, public Validator(Func<ValidationEvent, bool > validator) { _validatorLamda = validator; } |
这里其实就是通过传递泛型委托,ValidationEvent在这里起了什么用?看到这里我真的没想明白,其实只要Action< IValidationResults >就能实现的东西,作者为什么要写的这么复杂,仅仅为了参数传递白加上一个ValidationEvent?比如下面实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | Action<IValidationResults> _action; public Validator(Action<IValidationResults> action) { _action = action; } public IValidationResults TestAction() { _lastValidationResults = new ValidationResults(); if (_action != null ) { _action(_lastValidationResults); } return _lastValidationResults; } var t = new Validator(errors => { Validation.IsEmail( "kishore@" , false , errors, "邮箱" ); Validation.IsUrl( "http://www" , false , errors, "网址" ); Validation.IsPhoneUS( "111-111-111" , false , errors, "电话" ); }); t. TestAction(); |
RulesList验证和Lamda验证的实现方式一样,就多了一个List< ValidationRuleDef >来保存Func < ValidationEvent ,bool>集合~!
CustomValidator自定义验证
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | public void Example6_Custom() { ComLib.IValidator validator = new MyCustomUserIdValidator( "admin" ); IValidationResults errors = new ValidationResults(); PrintErrors(validator.Validate()); PrintErrors(validator.Validate(errors)); PrintErrors(validator.ValidateTarget( "powerUser01" )); Print( "Both" , validator.Validate( "powerUser01" , errors)); } public class MyCustomUserIdValidator : Validator { /// <summary> /// Initialize the object to validate. /// </summary> /// <param name="userName"></param> public MyCustomUserIdValidator( string userName) { Target = userName; } /// <summary> /// Do some custom validation on a user name(string). /// </summary> /// <param name="validationEvent"></param> /// <returns></returns> protected override bool ValidateInternal(ValidationEvent validationEvent) { string id = ( string )validationEvent.Target; if ( string .IsNullOrEmpty(id)) { validationEvent.Results.Add( "Must supply a userid." ); return false ; } id = id.ToLower(); if (id == "admin" || id == "administrator" ) { validationEvent.Results.Add( "Admin user name is reserved, you can not use it." ); return false ; } if (id.Length < 2 || id.Length > 15) { validationEvent.Results.Add( "Must be between 2 >= username <= 15." ); return false ; } return true ; } } |
看到这里了,前面的疑问就一下子明白,所有的自定义验证类必须继承Validator,重写ValidateInternal方法,我们可以看到Validate都会调用ValidateInternal方法,而ValidateInternal方法来做出后的处理,前面的为什么要使用ValidationEvent,也是为了使所有的扩展,使用相同的参数,相同的方法, 这样的设计固然使模块代码风格一样,最大化的提高了代码的复用率,但是是否适合自己,得靠自己来权衡。
在认真的看完这个模块的所有设计和代码实现发现,确实做的很不错,也让我很有信心把这个用到公司的通用类库中,恩,后面还有很多,慢慢来吧罗马哪是一天能建成的~
-----后面的模块分析停止了,写到后面几个模块的时候觉得:
到这里的时候我觉得这个通用类库没有必要去深究其设计了,代码都设计的大同小异了,或者有某些地方的实现方法值得去研究,而且我也不想在去逐个去分析,浪费时间,而且本末倒置了,这个东西就是拿来用的~,CommnLibrary中各个模块耦合性太强,想单独抠出来还不容易,很多模块项目中都用不上,如果硬拿过来,觉得只会破坏现有代码结构,到现在为之,只把Cache,Collections,Email,Extensions,Feeds,Notifications,Queue,Types,Validation,Localization,Exceptions,Utilities模块给单独抠了出来使用,罢了罢了~
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· SQL Server 2025 AI相关能力初探
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库