• 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#真的是一门非常优雅的语言。

  • 相关阅读:
    一个列表如何根据另一个列表进行排序(数组的相对排序)
    汉诺塔问题
    python面向对象基础
    python爬虫
    软件开发目录规范
    python--->包
    编译python文件
    python文件的俩种用途
    python模块的搜索路径
    python 循环导入的问题
  • 原文地址:https://www.cnblogs.com/slyfox/p/7136252.html
Copyright © 2020-2023  润新知