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 目录 特性简介 使用特性 特性 ...
随机推荐
- 谁说码农不懂浪漫?js写的'老婆生日快乐'特效
一直被老婆抱怨不懂浪漫,老婆的生日又来了,老婆指着闺蜜空间上贴的老公做的胡萝卜心形浪漫晚餐告诉我:必须送她一份用心的礼物.我绞尽脑汁想出这么一法子,还是得用我们码农的独特方式,经过一天多的努力,终于做 ...
- 20155321 2016-2017-2 《Java程序设计》第七周学习总结
20155321 2016-2017-2 <Java程序设计>第七周学习总结 教材学习内容总结 Date/DateFormat Date是日期类,可以精确到毫秒. 构造方法 Date() ...
- 【leetcode 简单】 第八十七题 两整数之和
不使用运算符 + 和-,计算两整数a .b之和. 示例: 若 a = 1 ,b = 2,返回 3. class Solution: def getSum(self, a, b): "&quo ...
- Samba远程代码执行漏洞(CVE-2017-7494)复现
简要记录一下Samba远程代码执行漏洞(CVE-2017-7494)环境搭建和利用的过程,献给那些想自己动手搭建环境的朋友.(虽然已过多时) 快捷通道:Docker ~ Samba远程代码执行漏洞(C ...
- React Native新手入门
前言 React Native是最近非常火的一个话题,想要学习如何使用它,首先就要知道它是什么. 好像面对一个新手全面介绍它的文章还不多,我就归纳一下所有的资料和刚入门的小伙伴一起来认识它~ 将从以下 ...
- 【洛谷】P1445 没占到1444的愤怒
继续洛谷刷水日常,突然遇到一道不是很水的题目…… https://www.luogu.org/problem/show?pid=1445 题意:给定n(1<=n<=1000000),求方程 ...
- Linux 网络编程实例
/*socket->bind->listen->accept->recv/recvfrom->send/sendto->close 客户端:socket->c ...
- ActiveMQ:初见&安装试运行
官网:http://activemq.apache.org/ ActiveMQ是一个消息中间件,在大型互联网应用中有广泛的使用. 当前最新版本:5.15.4,发布于2018-05-22,开源.Apac ...
- scala中“_”的用法
参见链接 http://blog.csdn.net/i6448038/article/details/50017427
- tf.reduce_sum函数
>>> x=[[1,2,3],[23,13,213]] >>> xx=tf.reduce_sum(x) >>> sess.run(xx) 255 ...
