C# System.Attribute(验证类)
本文以一个项目中通用的验证类来举例说明如何使用自定义Attribute来扩展元数据。
在项目中,我们为了保证各个层次之间的松藕合,通常把在各个层次之间传递数据的封装在一个称为实体类的类中,比如ActionFrom
- using System;
- namespace AttributeTest
- {
- public class ActionForm
- {
- private string email = "";
- private string password = "";
- public string Email
- {
- get { return this.email; }
- set { this.email = value; }
- }
- public string Password
- {
- get { return this.password; }
- set { this.password = value; }
- }
- }
- }
现在,在使用这些实体类中的数据之前,我们需要对其中的数据进行验证。通常我们会写个静态类,用来提供各种不同的验证方法。比如需要验证Email,验证Password,比如:
- using System;
- using System.Reflection;
- using System.Text.RegularExpressions;
- namespace AttributeTest
- {
- public class Validator
- {
- public static bool ValidateEmail(string email)
- {
- //方法体
- }
- public static bool ValidatePassword(string passwd)
- {
- //方法体
- }
- }
- }
这样的硬编码混迹于各个层次之间,一旦实体类里某个属性发生变化,就不得不修改各个层次中的相关验证代码。于是,我们想到可以使用一个统一的验证方法用来验证所有的实体类中的属性。
- public static bool Validate(string propertyName, string propertyValue, Validator.ValidateType t) {...}
这里,Validator.ValidateType 是Validator中提供的一个枚举。
- public enum ValidateType
- {
- Email,
- Password,
- Number,
- Id
- }
这里这个验证方法,的第三个参数使得验证与实体类的耦合密度增加了。我们还是不得不在修改实体类的时候,修改验证方法的调用代码。
现在,我们需要自定义Attribute来扩展实体类的元数据。通过对实体类元数据的描述,我们可以去掉验证方法里的第三个参数
- using System;
- namespace AttributeTest
- {
- [System.AttributeUsage(AttributeTargets.Property)]
- public class ValidateAttribute : System.Attribute
- {
- public ValidateAttribute(ValidateType validateType)
- {
- this.validateType = validateType;
- }
- private ValidateType validateType;
- public ValidateType ValidateType
- {
- get { return this.validateType; }
- set { this.validateType = value; }
- }
- }
- public enum ValidateType
- {
- Email,
- Password,
- Number,
- Id
- }
- }
自定义Attribute(特性)必须继承于System.Attribute。还可以通过System.AttributeUsageAttribute特性,控制自定义特性的使用范围(构件),例如,字段、方法。[System.AttributeUsage(AttributeTargets.Property)]限制这个自定义特性只能使用在类的属性上。
现在,我们实现这个验证方法:
- using System;
- using System.Reflection;
- using System.Text.RegularExpressions;
- namespace AttributeTest
- {
- public class Validator
- {
- public static bool Validate(object validateObject, string validateProperty)
- {
- System.Type t = validateObject.GetType();
- PropertyInfo pi = t.GetProperty(validateProperty);
- string validateValue = pi.GetValue(validateObject, null) as string;
- if (pi.IsDefined(typeof(ValidateAttribute), true))
- {
- object[] atts = pi.GetCustomAttributes(true);
- ValidateAttribute vatt = atts[0] as ValidateAttribute;
- string strExpr = "";
- switch (vatt.ValidateType)
- {
- case ValidateType.Email:
- strExpr = @"^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+{1}quot;;
- break;
- case ValidateType.Password:
- strExpr = @"\d{6}";
- break;
- case ValidateType.Number:
- strExpr = @"^\d*{1}quot;;
- break;
- case ValidateType.Id:
- strExpr = @"^\w*{1}quot;;
- break;
- default:
- return true;
- }
- Regex validateRegex = new Regex(strExpr);
- return validateRegex.IsMatch(validateValue);
- }
- return true;
- }
- }
- }
该方法需要两个参数,一个是需要验证的实体类的实例,还有一个是需要验证的属性名。当然,我们还需要在实体类上加上我们自定义的特性:
- using System;
- namespace AttributeTest
- {
- public class ActionForm
- {
- private string email = "";
- private string password = "";
- [Validate(ValidateType.Email)]
- public string Email
- {
- get { return this.email; }
- set { this.email = value; }
- }
- [Validate(ValidateType.Password)]
- public string Password
- {
- get { return this.password; }
- set { this.password = value; }
- }
- }
- }
我们通过自定义特性对实体类的元数据进行扩展,指定每个属性需要验证的类型。
现在我们可以这样使用这个验证类:
- ActionForm form = new ActionForm();
- form.Email = justacoder@123.com;
- form.Password = "123456";
- bool isValidEmail = Validator.Validate(form, "Email");
- bool isValidPassword = Validator.Validate(form, "Password");
- Console.WriteLine("Email is {0}.", isValidEmail?"valid":"invalid");
- Console.WriteLine("Password is {0}.", isValidPassword?"valid":"invalid");
- Console.ReadLine();
我们通过抛出自定义异常的方法,将验证扩大到实体类级别的验证:
- public static void ValidateProperty(object validateObject, string validateProperty)
- {
- System.Type t = validateObject.GetType();
- PropertyInfo pi = t.GetProperty(validateProperty);
- string validateValue = pi.GetValue(validateObject, null) as string;
- if( pi.IsDefined(typeof(ValidateAttribute), true) )
- {
- object[] atts = pi.GetCustomAttributes(true);
- ValidateAttribute vatt = atts[0] as ValidateAttribute;
- string strExpr = "";
- switch(vatt.ValidateType)
- {
- case ValidateType.Email:
- strExpr = @"^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+{1}quot;;
- break;
- case ValidateType.Password:
- strExpr = @"\d{6}";
- break;
- case ValidateType.Number:
- strExpr = @"^\d*{1}quot;;
- break;
- case ValidateType.Id:
- strExpr = @"^\w*{1}quot;;
- break;
- default:
- return;
- }
- Regex validateRegex = new Regex(strExpr);
- if( !validateRegex.IsMatch(validateValue) )
- {
- throw new ApplicationException(validateProperty + " is invalid.");
- }
- }
- }
- public static void Validate(object validateObject)
- {
- System.Type t = validateObject.GetType();
- PropertyInfo[] ps = t.GetProperties();
- foreach(PropertyInfo pi in ps)
- {
- ValidateProperty(validateObject, pi.Name);
- }
- }
现在验证,只需要这样:
- try
- {
- Validator.Validate(form);
- }
- catch(Exception ex)
C# System.Attribute(验证类)的更多相关文章
- C# 通用验证类 支持 WPF,MVC,Winform
验证方式, 通过继承 IDataErrorInfo接口 和 DataAnnotations 解释标记语言而实现, 为了能在WPF上通用,所了也要继承属性更改通知接口INotifyPropertyC ...
- C# - DataValid数据验证类
从EasyCode 摘取下来的数据验证类 using System; using System.Collections.Generic; using System.Text; namespace Le ...
- 做一个牛XX的身份证号验证类(支持15位和18位)
原文:做一个牛XX的身份证号验证类(支持15位和18位) #region 是否合法的中国身份证号码 protected bool IsChineseID() { if (str.Length == 1 ...
- JavaScript 数据验证类
JavaScript 数据验证类 /* JavaScript:验证类 author:杨波 date:20160323 1.用户名验证 2.密码验证 3.重复密码验证 4.邮箱验证 5.手机号验证 6. ...
- System.IO.Directory类
1.参考的博客:System.IO.Directory类和System.DirectoryInfo类(http://blog.sina.com.cn/s/blog_614f473101017du4.h ...
- 使用System.Timers.Timer类实现程序定时执行
使用System.Timers.Timer类实现程序定时执行 在C#里关于定时器类有3个:System.Windows.Forms.Timer类.System.Threading.Timer类和Sys ...
- php表单数据验证类
非常好用方便的表单数据验证类 <?php //验证类 class Fun{ function isEmpty($val) { if (!is_string($val)) return false ...
- 详解C#中System.IO.File类和System.IO.FileInfo类的用法
System.IO.File类和System.IO.FileInfo类主要提供有关文件的各种操作,在使用时需要引用System.IO命名空间.下面通过程序实例来介绍其主要属性和方法. (1) 文件打开 ...
- JS表单验证类HTML代码实例
以前用的比较多的一个JS表单验证类,对于个人来说已经够用了,有兴趣的可以在此基础上扩展成ajax版本.本表单验证类囊括了密码验证.英文4~10个 字符验证. 中文非空验证.大于10小于100的数字.浮 ...
随机推荐
- PHPstrom2016.1激活与汉化【2016.06.21依旧可用】
: 目前的网络上有很多的关于PHPstrom激活的方法,但是很多都失效了,没有具体的使用日期,这个是我从其他网友那里转载过来的,具体地址忘记了: 方法如下: 需要在联网条件下,打开PHPstrom,在 ...
- Ambry: LinkedIn’s Scalable Geo-Distributed Object Store
https://github.com/linkedin/ambry http://www.open-open.com/lib/view/open1464828607502.html
- wifidog编译到openwrt
首先敲一下 cd 命令,定位到自己的用户目录, 然后 mkdir openwrt 新建一个openwrt文件夹,然后开始装openwrt的编译用到的工具, sudo apt-get install g ...
- 由Double类型数据到数据的格式化包java.text
需求:Double类型数据截取操作保留两位小数 解决方案: java.text.DecimalFormat df =new java.text.DecimalFormat("#.00&quo ...
- Date、String、Calendar类型之间的转化
原文出处:http://fjfj910.iteye.com/blog/1202219 1.Calendar 转化 String //获取当前时间的具体情况,如年,月,日,week,date,分,秒等 ...
- asp.net <% %>,<%# %>,<%= %>,<%$ %>区别大集合
前台页面 <div><%--可以执行服务器代码,相当于在后台写代码,Render%><%=取后台变量或方法值,只能绑定客户端控件,绑定服务器控件时后来必须调用databi ...
- 基于BOOST 实现并发服务器框架
一:设计思路 本服务器框架使用 UDP 传输协议,程序柱线程等待客户端数据,并将数组存取队列缓冲区.另外可开启多个工作线程,工作线程可以依据具体项目实现不同的功能 ,例如可以将队列缓冲区中的数据逐个取 ...
- Substring的简单使用
string myString = "测试一下函数Substring()是怎么用的"; //Substring()在C#中有两个重载函数 //分别如下示例 //如果参数为一个长整数 ...
- data structure online video
http://www.onlinevideolecture.com/computer-science/nptel-iit-delhi/data-structures-and-algorithms/?c ...
- ASP.NET MVC got 405 error on HTTP DELETE request
使用Backload的时候在本地调试通过,上传服务器后出现405错误(监控通信时可以发现ajax的返回结果为405) 通过修改webconfig可以解决: <system.webServer&g ...