C#高级特性(三、Attribute特性)

1,987 阅读3分钟

一、特性在哪里应用?

特性是无处不在的,在EF-MVC-WebService-UnitTest等等,那么她长什么样子呢? [特性名称]

二、特性是个什么?

可以发现,特性就是一个类,直接或间接继承自Attribute父类。

三、自定义特性

系统自带的特性就不用说了,那么我们可不可以自己定义一个特性呢?当然可以!

自定义特性分为以下4步:

  • 声明自定义特性;
  • 构建自定义特性;
  • 在目标程序上应用自定义特性
  • 通过反射访问特性

开始操作

1、自定义一个检查长度是否符合规范的特性类

AttributeUsage

  • 预定义特性 AttributeUsage 描述了如何使用一个自定义特性类。它规定了特性可应用到的项目的类型。
[AttributeUsage(
   validon,
   AllowMultiple=allowmultiple,
   Inherited=inherited
)]

其中:

  • 参数 validon 规定特性可被放置的语言元素。它是枚举器 AttributeTargets 的值的组合。默认值是 AttributeTargets.All。
  • 参数 allowmultiple(可选的)为该特性的 AllowMultiple 属性(property)提供一个布尔值。如果为 true,则该特性是多用的。默认值是 false(单用的)。
  • 参数 inherited(可选的)为该特性的 Inherited 属性(property)提供一个布尔值。如果为 true,则该特性可被派生类继承。默认值是 false(不被继承)。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AttributeDemo
{
    [AttributeUsage(AttributeTargets.Property)]//约束特性只能给属性声明
    public class StringLengthAttribute: Attribute //继承父类,约定俗成以Attribute结尾
    {
        private int Min;
        private int Max;
        public StringLengthAttribute(int min,int max)//调用特性时给字段赋值
        {
            this.Min = min;
            this.Max = max;
        }
        public bool Validate<T>(T t)
        {
            //传入的值不能为空,大于最小长度,小于最长长度,字符串符合返回True,否则False
            return t != null && t.ToString().Length >= Min && t.ToString().Length <= Max;
        }
    }
}


2、建立一个用户类,并且添加特性

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AttributeDemo
{
    public class UsersInfo
    {
        /// <summary>
        /// 用户账号
        /// </summary>
        [StringLength(5,15)]//Attribute可以省略
        public string Account { get; set; }
    }
}

3、建立一个第三方类,来反射获取特性,执行里面的方法

通过反射遍历类型的属性,检测是否存在特性,存在就执行特性的方法,返回值

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace AttributeDemo
{
    public static class AttributeExend//特性扩展类,第三方类
    {
        public static bool Validate<T>(this T t)//使用扩展方法
        {
            Type type = t.GetType();//获取类型
            foreach (var prop in type.GetProperties())//遍历类型的属性
            {
                if (prop.IsDefined(typeof(StringLengthAttribute), true))//检查特性是否存在
                {
                    //存在的话获取特性
                    StringLengthAttribute attribute = (StringLengthAttribute)prop.GetCustomAttribute(typeof(StringLengthAttribute), true);
                    //执行特性的方法,传递当前属性的值过去
                    return attribute.Validate(prop.GetValue(t));//检查是否符合特性,返回方法的值
                }
            }
            
            return true;//没有特性就返回true
        }
    }
}

4、客户端调用

 UsersInfo users = new UsersInfo();
            users.Account = "1123213";
            if (users.Validate())//这返回的是一个bool值,true代表验证通过,false没有
            {
                Console.WriteLine("验证成功");
            }
            else
            {
                Console.WriteLine("请输入5-15的字符串");
            }

四、自我理解

  • 我们会发现特性本身是没有用的。
  • 我们只能通过反射获取特性,先isdefind检测,在获取
  • 程序运行的时候就可以找到特性,就可以发挥特性的作业,提供额外的信息,或额外的动作。
  • 所以,我们需要一个第三方,在这里去主动检测特性,并提供功能。
  • 特性本身是没有用的

五、结束语

你不能拥有的,别人替你去拥有