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的数字.浮 ...
随机推荐
- Jquery ajax使用json形式通信
前台JS $.ajax({ type: 'post', url: 'HandlerL ...
- 实现一个div在浏览器水平居中
第一种方法: div { margin: 0 auto; width: 960px; } 第二种方法(兼容IE): body { text-align: center; } div { margin: ...
- POJ1182并查集
食物链 时间限制:1000 ms | 内存限制:65535 KB 难度:5 描述 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物, ...
- MVC5之路由机制
---恢复内容开始--- MVC是一种模式,是基于asp.net上的一种设计.路由机制不属于MVC,路由机制属于asp.net.因此,mvc的路由机制就是基于asp.net路由机制上的一种“自定制”. ...
- 解决php json_encode 出现的中文转码、乱码问题
// 防止json中文转码 function jsonEncodeWithCN($data) { return preg_replace("/\\\u([0-9a-f]{4})/ie&quo ...
- Interface的多层继承
我有一段如下代码,定义一个接口iInterface,cBase实现iInterface,cChild继承cBase,UML为 预期是想要cBase.F()的执行逻辑,同时需要cChild的返回值,所以 ...
- MaskedTextBox控件实现输入验证
Mask属性可以验证用户在文本中输入数据的格式 this.maskedTextBox1.Mask = "000000-00000000-000A";//身份证号码18位 this. ...
- 如何在 Java 中正确使用 wait, notify 和 notifyAll – 以生产者消费者模型为例
wait, notify 和 notifyAll,这些在多线程中被经常用到的保留关键字,在实际开发的时候很多时候却并没有被大家重视.本文对这些关键字的使用进行了描述. 在 Java 中可以用 wait ...
- .net faq
http://www.indiabix.com/technical/dotnet/ http://www.codeproject.com/Articles/637480/Csharp-and-ASP- ...
- iOS 8 定位失败问题
首先plist定义两个string: NSLocationWhenInUseUsageDescription NSLocationAlwaysUsageDescription 然后调用 [self. ...