.Net 特性(Attribute)

特性Attribute,和注释有什么区别

  1. 注释:是让人看的懂代码,不影响程序的运行,和编译器
  2. 特性:特性可以影响编译器,特性可以影响程序的运行,特性编译后生成的是一个metadata
		[Obsolete(请不要用这个了,请使用什么来代替,true)]  //过时了 可以用来标记已经不用了的方法,
		[Serializable] //可以序列化和反序列化

声明和使用attribute,AttributeUsage

  1. 声明和使用
  • 特性:特性是一个 直接/间接 继承attribute的类。约定俗成的用Attribute结尾,然后声明的时候可以省略
  • 特性可以修饰类,字段,属性,方法,参数,返回值([return:名称]), 基本上所有的元素上都可以修饰
  • 特性在声明得时候还可以直接给自己得属性或字段赋值
		[Custom("这是一个学生",ID=1234)]
		[Custom(Name="学生",Remark="备注")]
		public class Student
		{
			[Custom]
			public int ID { get; set; }
			[Custom]
			[RequirdValidate]//非空验证
        	public string Name { get; set; }
       		[Custom]//qq号长度验证
       		[LongValidate(10000,99999999999)]
        	public long QQ { get; set; }
        	[Custom]
        	public string QQ_password { get; set; }
        	[Custom]
        	public string Remark { get; set; }
        
			[Custom]
        	public Student() { Console.WriteLine("这里是student类"); }

        /// <summary>
        /// 展示字段的值
        /// </summary>
        [Custom]
        public void Show()
        {
            Console.WriteLine($"ID={ID},Name={Name},QQ={QQ},QQ密码={QQ_password},Remark={Remark}");
        }
        /// <summary>
        /// 自我介绍
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        [Custom]
        [return:Custom]
        public string SelfIntroduction(string name)
        {
            return $"你好,我是{name}";
        }
		}
  1. AttributeUsage
    这个特性用来修饰特性,可以修来约束特性的范围,是否可以多重修饰,子类是否是特效
    AttributeTargets 特性的目标、AllowMultiple 多重修饰,默认false、Inheriter 子类是否是特性,默认true、一般不会重复修饰,没又意义
	[AttributeUsage(AttributeTargets.All,AllowMultiple=false,Inheriter=true)]
	public class CustomAttribute : Attribute
	{
		public CustomAttribute()
		{
			
		}
		public CustomAttribute(string name)
		{
			this.Name=name;
		}
		public int ID{get;set;}
		public string Name{get;set;}
		public string Remark{get;set;}
	}

注意:特性在我们不使用的时候一点用都没有,就跟注释差不多,特性本身是毫无价值的
如何使用:特性编译后生成的是一个metadata,只有使用反射才有用

运行中获取Attribute:额外信息 额外操作

特性在声明后,本身是没有用的,对我们的程序是没有影响的
除非我们在使用的过程中主动去找它,主动找它的过程中是通过反射的方式,找的时候才会去实例化这些特性

 Student student = new Student();
            student.ID = 1;
            student.Name = "小明";
            student.QQ = 927281458;
            student.QQ_password = "123";
            student.Remark = "我是一个小学生!";
            

如何主动去调用特性


            //主动
			//使用反射去调用
            Type type = student.GetType();

            if (type.IsDefined(typeof(CustomAttribute), true))//检测有没有这个特性
            {
                object item = type.GetCustomAttributes(typeof(CustomAttribute), true)[0];
                //foreach (var item in type.GetCustomAttributes(typeof(CustomAttribute), true))
                {
                    CustomAttribute attribute = item as CustomAttribute;
                    attribute.Show();
                }
            }
            foreach (var item in type.GetProperties())//属性
            {
                if (item.IsDefined(typeof(CustomAttribute), true))//检查该属性是否有这个特性
                {
                    object oAttribute = item.GetCustomAttributes(typeof(CustomAttribute), true)[0];
                }
            }
            foreach (var item in type.GetFields())//字段
            {
                if (item.IsDefined(typeof(CustomAttribute), true))//检查该字段是否有这个特性
                {
                    object oAttribute = item.GetCustomAttributes(typeof(CustomAttribute), true)[0];
                }
            }
            foreach (var item in type.GetConstructors())//构造函数
            {
                if (item.IsDefined(typeof(CustomAttribute), true))
                {
                    object oAttribute = item.GetCustomAttributes(typeof(CustomAttribute), true)[0];
                }
            }
            MethodInfo method = type.GetMethod("SelfIntroduction");//获取这个方法
            if (method.IsDefined(typeof(CustomAttribute), true))
            {
                object item = method.GetCustomAttributes(typeof(CustomAttribute), true)[0];
            }

            foreach (var item in method.GetParameters())//这个SelfIntroduction方法的 所有参数
            {
                if (item.IsDefined(typeof(CustomAttribute), true))
                {
                    object oAttribute = item.GetCustomAttributes(typeof(CustomAttribute), true)[0];
                }
            }
            if (method.ReturnParameter.IsDefined(typeof(CustomAttribute), true))//返回参数是否有这个属性
            {
                object oAttribute = method.ReturnParameter.GetCustomAttributes(typeof(CustomAttribute), true)[0];
            }

自定义特性


/// <summary>
    /// 自定义特性
    /// </summary>
    [AttributeUsage(AttributeTargets.All)]//AttributeTargets.All 所有元素
    public class CustomAttribute : Attribute
    {
		public CustomAttribute()
		{
			Console.WriteLine("这是一个无参数的构造函数");
		}
		public CustomAttribute(string name)
		{
			this.Name = name;
			Console.WriteLine("这是一个有参数的构造函数");
		}
		public int ID { get; set; }
		public string Name { get; set; }
		public string Remark { get; set; }

		public void Show()
		{
			Console.WriteLine($"ID={ID},Name={Name},Remark={Remark}");
		}
	}
	

请看下面这个实列:

  • 我们创建一个特性RemarkAttribute,继承Attribute,在创建一个UserState用户状态的枚举,和一个RemarkExtend的扩展类,提供一个扩展方法 GetRemark() 用于获取枚举的一个额外信息。
  • 如何调用,如下
    RemarkExtend.GetRemark(UserState.Deleted); //得到的是删除
    或者 UserState.Deleted.GetRemark();//得到的是删除
/// <summary>
    /// 是给枚举用  提供一个额外信息
    /// </summary>
    [AttributeUsage(AttributeTargets.Enum | AttributeTargets.Field)]
    public class RemarkAttribute : Attribute
    {
        public RemarkAttribute(string remark)
        {
            this.Remark = remark;
        }

        public string Remark { get; private set; }
    }

    public static class RemarkExtend
    {
        /// <summary>
        /// 扩展方法
        /// </summary>
        /// <param name="enumValue"></param>
        /// <returns></returns>
        public static string GetRemark(this Enum enumValue)
        {
            Type type = enumValue.GetType();
            FieldInfo field = type.GetField(enumValue.ToString());
            if (field.IsDefined(typeof(RemarkAttribute), true))
            {
                RemarkAttribute remarkAttribute = (RemarkAttribute)field.GetCustomAttribute(typeof(RemarkAttribute));
                return remarkAttribute.Remark;
            }
            else
            {
                return enumValue.ToString();
            }
        }
    }

    [Remark("用户状态")]
    public enum UserState
    {
        /// <summary>
        /// 正常
        /// </summary>
        [Remark("正常")]
        Normal = 0,
        /// <summary>
        /// 冻结
        /// </summary>
        [Remark("冻结")]
        Frozen = 1,
        /// <summary>
        /// 删除
        /// </summary>
        [Remark("删除")]
        Deleted = 2
    }


在来看我们另外的一个实列:非空验证和长度验证

  • 创建特性AbstractValidateAttribute用类验证数据的特性
  • 创建一个LongValidateAttribute验证长度的特性继承AbstractValidateAttribute,并实现其中的方法
  • 创建一个RequirdValidateAttribute验证非空的特性继承AbstractValidateAttribute,并实现其中的方法
  • 创建一个DataValidate的扩展类并扩展一个Validate的扩展方法,返回一个bool类型的值,当属性字段不满足要求时,会返回一个false

/// <summary>
    /// 验证数据特性
    /// </summary>
    public abstract class AbstractValidateAttribute : Attribute
    {
        public abstract bool Validate(object oValue);
    }
    /// <summary>
    /// 验证长度特性
    /// </summary>
    public class LongValidateAttribute : AbstractValidateAttribute
    {
        private long _lMin = 0;
        private long _lMax = 0;
        public LongValidateAttribute(long lMin, long lMax)
        {
            this._lMin = lMin;
            this._lMax = lMax;
        }
        /// <summary>
        /// 输入得值是否在这个范围类
        /// </summary>
        /// <param name="oValue"></param>
        /// <returns></returns>
        public override bool Validate(object oValue)
        {
            return _lMin <= (long)oValue && (long)oValue >= _lMax;
        }
    }
    /// <summary>
    /// 验证是否非空特性
    /// </summary>
    public class RequirdValidateAttribute : AbstractValidateAttribute
    {
        public override bool Validate(object oValue)
        {
            return oValue != null;
        }
    }

    public static class DataValidate
    {
        public static bool Validate<T>(T t)//验证数据是否正确
        {
            Type type = t.GetType();
            bool result = true;
            foreach (var prop in type.GetProperties())//取得该类得属性的信息
            {
                if (prop.IsDefined(typeof(AbstractValidateAttribute), true))//该属性是否存在AbstractValidateAttribute这条特性
                {
                    object item = prop.GetCustomAttributes(typeof(AbstractValidateAttribute), true)[0];//获取当前属性得AbstractValidateAttribute特性对象 返回得是应该object
                    AbstractValidateAttribute attribute = item as AbstractValidateAttribute;
                    if (!attribute.Validate(prop.GetValue(t)))//prop.GetValue(t) 当前属性得值
                    {
                        result = false;
                        break;
                    }
                }
            }

            return result;

        }
    }


总结:
特性:是一个类,可以用来标记元素,编译时生成到metadata里,平时不影响程序的运行除非主动用反射去查找,可以得到一些额外的信息/操作,然后提供了更丰富的扩展空间。

特性可以在不破坏类型封装的前提下,额外的增加功能

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值