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的数字.浮 ...
随机推荐
- linux中 ECShop的文件不能写
解决办法: 1.开放权限 使用命令:chmod -R 777 文件路径 2.关闭SELinux 使用命令:setenforce 0
- resid入门笔记(二)
本节介绍redis 消息订阅 密码 持久化 主从配置 首先我对消息订阅理解的不深,应该说仅知道概念吧 发送消息 cctv1 发送 hello cctv2 发送 ‘你好’ client ...
- jQuery入门[1]-构造函数【转载】
最近看了一些jquery的进阶教程,感觉很不错,与大家分享下! jQuery——构造函数 ◦体积小(v1.2.3 15kb)◦丰富的DOM选择器(CSS1-3 + XPath) ◦跨浏览器(IE6,F ...
- object-fit: 炒鸡方便的图片居中方法
今天在项目中遇到图片居中的问题,嗯,之前也有写过解决这个问题的文章,有n种方法.不过今天要说一个新的方案:object-fit ,嗯,这个才是真的方便的方案啊. 先看预览: object-fit 只能 ...
- 3.MVC框架开发(Razor内嵌函数)
1.建立没有返回值的Razor内嵌函数(但是能直接输出内容) 必须以@符号开头,没有返回值但能直接输出内容,比如: @helper showTitle(string strTitle){ ){ @(s ...
- CODEVS 1004四子连棋
[题目描述 Description] 在一个4*4的棋盘上摆放了14颗棋子,其中有7颗白色棋子,7颗黑色棋子,有两个空白地带,任何一颗黑白棋子都可以向上下左右四个方向移动到相邻的空格,这叫行棋一步,黑 ...
- WindowsPhone客户端第一次审核失败记录
微软返回失败pdf,其中2.7.2和2.7.3没有通过,原因是: 1. 没有提供隐私策略,所以在提交App要填写的隐私策略url里加了隐私策略的网址链接. 2. 由于使用了定位服务,所以第一次进入应用 ...
- fatal error C1853
http://myswirl.blog.163.com/blog/static/513186422011827105224739/ 预编译头文件来自编译器的早期版本,或者预编译头为 C++ 而在 C ...
- delphi xe5 android iny绿色版+最新SDK/NDK安装方法
转自: http://bbs.2ccc.com/topic.asp?topicid=438595 首先感谢iny的绿色版,因为我的精简Win7 32位安装原版镜像4.63G过程正常,但是编译出错,后来 ...
- 《暗黑世界GM管理后台系统》部署+功能说明
原地址:http://blog.csdn.net/uxqclm/article/details/11969761 欢迎来到9秒:www.9miao.com 暗黑三国管理后台说明文档 (一)功能描述该后 ...