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 ... 
 
			
		