C#中的特性 (Attribute) 入门 (二)
C#中的特性 (Attribute) 入门 (二)
接下来我们要自己定义我们自己的特性,通过我们自己定义的特性来描述我们的代码。
自定义特性
所有的自定义特性都应该继承或者间接的继承自
Attribute类。我们在项目开发中经常要写类的创建人的注释,今天我们我们要用自定义Attribute来做这件事。
上一章,我们学到了AttributeUsage ,我们知道该特性是用描述特性的
Step 1 建立一个class 继承自Attribute
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AuthorAttribute
{
/// <summary>
/// 用于对类的描述,该特性只能作用于类
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class AuthorAttribute : Attribute
{
private string _author;
private string _dateTime;
private double _versionCode;
private string _remark;
/// <summary>
/// 建立对类描述的attribute
/// </summary>
/// <param name="author">作者</param>
/// <param name="dateTime">创建时间</param>
/// <param name="versionCode">版本号</param>
/// <param name="remark">藐视信息</param>
public AuthorAttribute(string author, string dateTime, double versionCode, string remark)
{
this.Author = author;
this.DateTime = dateTime;
this.VersionCode = versionCode;
this.Remark = remark;
}
/// <summary>
/// 设置或者获取该类的创建人信息
/// </summary>
public string Author
{
get
{
return _author;
}
private set
{
_author = value;
}
}
/// <summary>
/// 获取或设置类的创建时间
/// </summary>
public string DateTime
{
get
{
return _dateTime;
}
private set
{
_dateTime = value;
}
}
/// <summary>
/// 类的版本号
/// </summary>
public double VersionCode
{
get
{
return _versionCode;
}
private set
{
_versionCode = value;
}
}
/// <summary>
/// 获取或设置类的描述信息
/// </summary>
public string Remark
{
get
{
return _remark;
}
private set
{
_remark = value;
}
}
}
}
Step 2 : 我们来使用我们上面定义好的特性
[Author("鲁迅认识的那只猹", "2017-07-08", 1.0, "建立Student类,用来存储学生的信息")]
[Author("鲁迅认识的那只猹", "2017-07-08", 1.001, "为Student类添加了【DateOfBirth】属性")]
public class Student
{
public string Name { get; set; }
public string Gender { get; set; }
public DateTime DateOfBirth { get; set; }
}
Step 3 上面我们已经标注好了我们的类,然后我们要获取我们的描述
static void Main(string[] args)
{
Type type = typeof(Student);
//获取到Student类的所有特性
object[] objs = type.GetCustomAttributes(true);
//循环判断我们我们获取到的objs数组
foreach (object item in objs)
{
AuthorAttribute attr = item as AuthorAttribute;
if (attr != null)
Console.WriteLine
(
"Author:" + attr.Author
+ " Version Code:" + attr.VersionCode
+ " Date Time:" + attr.DateTime
+ " Remark:" + attr.Remark
);
}
Console.ReadKey();
}
/*输出结果
Author:鲁迅认识的那只猹 Version Code:1 Date Time:2017-07-08 Remark:建立Student类,用来存储学生的信息
Author:鲁迅认识的那只猹 Version Code:1.001 Date Time:2017-07-08 Remark:为Student类添加了【DateOfBirth】属性
*/
到此我们应该已经对自定义特性有了一个简单的了解,下面我们将用自定义Attribute来做一件很cool的事情。
Cool 的事情
我们在开发中经常被数据验证所困扰,对我们来说是一个非常重复而且无聊的事情是,我们来改善一下这个事。
效果:
设计思路:
- 使用我们的自定义特性对方法进行描述
- 在我们的自定义特性重,实现数据验证的方法
- 将特性判断封装为一个方法,在所有需要调用进行验证的时候,都调用此方法来进行判断如果不符合就抛出异常。
实现
Step 1: 建立一个用来判断参数的父类,所有的用于验证的Attribute都将继承自此类。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DataValidateAttribute
{
/// <summary>
/// 所有验证类特性的父类,所有的用于验证的特性都将继承此类
/// </summary>
/*
AttributeTargets.Parameter 标识该特性作用于 方法的参数
Inherited = true 标识该特性可以被继承
AllowMultiple = true 标识可以多次标注
*/
[AttributeUsage(AttributeTargets.Parameter, Inherited = true, AllowMultiple = true)]
public abstract class ValidateAttribute
: Attribute
{
public ValidateAttribute()
{
}
public ValidateAttribute(string msg)
{
this.Message = msg;
}
/// <summary>
/// 被验证的参数名称
/// </summary>
private string _argumentName;
/// <summary>
/// 抛出错误的信息
/// </summary>
private string _message;
/// <summary>
/// 获取被验证的参数名称
/// </summary>
public string ArgumentName
{
set
{
_argumentName = value;
}
protected get
{
return _argumentName;
}
}
/// <summary>
/// 异常的提示信息
/// </summary>
public string Message
{
protected get
{
return _message;
}
set
{
_message = value;
}
}
/// <summary>
/// 验证该值是否符合指定的规则
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public abstract void IsValidation(object value);
}
}
Step 2: 实现我们的验证用的子类
[NotNullAttribute]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DataValidateAttribute
{
public class NotNullAttribute : ValidateAttribute
{
public NotNullAttribute()
{
}
public NotNullAttribute(string msg) : base(msg)
{
}
public override void IsValidation(object value)
{
if (value == null)
{
throw new ArgumentNullException(this.ArgumentName + " " + Message);
}
}
}
}
[ValidationAgeAttribute]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DataValidateAttribute
{
public class ValidationAgeAttribute : ValidateAttribute
{
public ValidationAgeAttribute()
{
}
public ValidationAgeAttribute(string msg) : base(msg)
{
}
public override void IsValidation(object value)
{
int age = Convert.ToInt32(value);
if (age <= 0)
{
throw new ArgumentException(this.ArgumentName + " " + this.Message);
}
}
}
}
Step 3 抽取一个统一使用的用于验证的方法:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace DataValidateAttribute
{
public static class ValidateContext
{
/// <summary>
/// 验证方法的参数是否合法
/// </summary>
/// <param name="values">被判断的值,值得顺序必须按照参数特性的顺序来传值</param>
public static void Validate(object[] values)
{
//从方法栈中拿到刚执行的方法
MethodInfo method = (MethodInfo)(new StackTrace().GetFrame(1).GetMethod());
//获取到方法的参数
ParameterInfo[] parameterInfos = method.GetParameters();
if (parameterInfos.Length == 0)
return;
int index = 0;
//遍历所有的参数
foreach (var item in parameterInfos)
{
//获取被标记的特性的数组
ValidateAttribute[] attributes = (ValidateAttribute[])Attribute.GetCustomAttributes(item, typeof(ValidateAttribute));
if (attributes != null)
{
foreach (var attr in attributes)
{
//如果没有异常就证明验证通过
try
{
attr.ArgumentName = item.Name;
attr.IsValidation(values[index]);
}
//如果有异常那么就表示验证没有通过,抛出我们指定的异常
catch (Exception e)
{
throw e;
}
}
index += 1;
}
}
}
}
}
Step 5 检验效果:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DataValidateAttribute
{
class Program
{
static void Main(string[] args)
{
Console.ReadKey();
}
/// <summary>
/// 普通方式来验证参数的方法
/// </summary>
/// <param name="name"></param>
/// <param name="gender"></param>
/// <param name="age"></param>
static void Dome1(string name, string gender, int age)
{
if (name == null)
{
throw new ArgumentNullException("name");
}
if (gender == null)
{
throw new ArgumentNullException("gender");
}
if (age <= 0)
{
throw new ArgumentException("age");
}
}
/// <summary>
/// 使用特性来验证参数的方法
/// </summary>
/// <param name="name"></param>
/// <param name="gender"></param>
/// <param name="age"></param>
static void Demo2([NotNull("名字你还想空?")]string name, [NotNull]string gender, [ValidationAge("年龄错误 不能小于0")]int age)
{
ValidateContext.Validate(new object[] { name, gender, age });
}
}
}
效果图:
抛出我们已经定义好了的异常,以后只要是相同的判断,我们就只要对其进行标注一下调用统一的判断方法即可。

Summary
到此Attribute相信你已经基本上掌握了,文中有何不足之处还望指出,大家共同学习,共同进步,C#真的是一门非常优雅的语言。
C#中的特性 (Attribute) 入门 (二)的更多相关文章
- C#中的特性 (Attribute) 入门 (一)
C#中的特性 (Attribute) 入门 (一) 饮水思源 http://www.cnblogs.com/Wind-Eagle/archive/2008/12/10/1351746.html htt ...
- c#核心基础 - 浅谈 c# 中的特性 Attribute)
特性(Attribute)是用于在运行时传递程序中各种元素(比如类.方法.结构.枚举.组件等)的行为信息的声明性标签.可以通过使用特性向程序添加声明性信息.一个声明性标签是通过放置在它所应用的元素前面 ...
- c#中的特性Attribute
一:特性是什么?特性怎么创建怎么使用? 这一章节,我想谈谈c#的特性方面的知识,特性大家在工作开发中都很熟悉,比如我们经常见到的 1:key Display --EF 2:Import 3:HttpG ...
- c#特性attribute:(二)
日志 初始化 特性类里边构造函数里的属性,带参数不带参数的 ******特性是编译时是不加到il 中的,是加到metadata中 ,本身对程序运行没有影响,除非我们主动的读取和使用区供反射可以使用. ...
- .net 4.0 中的特性总结(二):默认参数、命名参数
1.在方法定义的时候为参数指定一个默认值.调用方法的时候既可以像平时那样传入参数,也可以直接跳过不传入,这样的话,就使用默认值传到方法里.例如: 2.在之前版本的C#中,方法定义的参数顺序必须与方法调 ...
- .net中的特性
本文来之:http://hi.baidu.com/sanlng/item/afa31eed0a383e0e570f1d3e 在一般的应用中,特性(Attribute,以称为属性)好像被使用的不是很多. ...
- 在.Net Core中使用MongoDB的入门教程(二)
在上一篇文章中,讲到了MongoDB在导入驱动.MongoDB的连接,数据的插入等. 在.Net Core中使用MongoDB的入门教程(一) 本篇文章将接着上篇文章进行介绍MongoDB在.Net ...
- [C#] 剖析 AssemblyInfo.cs - 了解常用的特性 Attribute
剖析 AssemblyInfo.cs - 了解常用的特性 Attribute [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/5944391.html 序 ...
- [C#] C# 知识回顾 - 特性 Attribute
C# 知识回顾 - 特性 Attribute [博主]反骨仔 [原文地址]http://www.cnblogs.com/liqingwen/p/5911289.html 目录 特性简介 使用特性 特性 ...
随机推荐
- mysql sql优化实例1(force index使用)
今天和运维同学一块查找mysql慢查询日志,发现了如下一条sql: SELECT sum(`android` + ios) total,pictureid,title,add_time FROM `j ...
- beta版1.1.1
先期发布的alpha版1.0.0版本通过张硕组的测评,我小组跟进修改了出现的问题. 1.首先解决了互测版本中无法正常退出界面的问题,并有退出提示,(确定,取消). 2.就之前提到的关于前期部分功能的割 ...
- 学号20155308 2016-2017-2 《Java程序设计》第6周学习总结
学号20155308 2016-2017-2 <Java程序设计>第6周学习总结 教材学习内容总结 第十章 输入与输出 目的:文件的读写:网络上传数据的基础:同样要掌握父类中方法. 10. ...
- linux安装rz,sz命令
安装方法: yum install lrzsz -y
- 原生的js实现jsonp的跨域封装
一.原理 jsonp是利用浏览器请求script文件时不受同源策略的限制而实现的,伪造一个script标签,将请求数据的url赋值给script的src属性,并将该标签添加到html中,浏览器会自动发 ...
- iframe 同域下父子页面的通信
//共同引用的JS文件 common.js ; (function (window, $) { $(function ($) { window.trip = window.trip || {}; wi ...
- python网络编程--线程Semaphore(信号量)
一:Semaphore(信号量) 互斥锁 同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据 ,比如厕所有3个坑,那最多只允许3个人上厕所,后面的人只能等里面有人出来了才 ...
- Unix IPC之互斥锁与条件变量
互斥锁 1.函数声明 #include <pthread.h> /* Mutex handling. */ /* Initialize a mutex. */ extern int pth ...
- 在windows中安装两个不同版本的Python
这段时间买了一本 利用Python进行数据分析的书.书上要我将原来安装的Python的环境去掉,但是我觉得这样做不行,我以前写过的很多东西还在呢.遂在博客中找到了解决方法,记录之. 首先,我们安装了两 ...
- Linux下堆漏洞的利用机制
1.保护机制 )) malloc_printerr (check_action, "corrupted double-linked list", P); 这个就是所谓的堆指针的ch ...
