• 特性


    1、什么是特性

      特性(Attribute)是用于在运行时传递程序中各种元素(比如类、方法、结构、枚举、组件等)的行为信息的声明性标签。可以通过使用特性向程序添加声明性信息。一个声明性标签是通过放置在它所应用的元素前面的方括号([ ])来描述的。使用特性,可以有效地将元数据或声明性信息与代码(程序集、类型、方法、属性等)相关联。 将特性与程序实体相关联后,可以在运行时使用反射这项技术查询特性。

      特性具有以下属性:

    1. 特性向程序添加元数据。 元数据是程序中定义的类型的相关信息。 所有 .NET 程序集都包含一组指定的元数据,用于描述程序集中定义的类型和类型成员。 可以添加自定义特性来指定所需的其他任何信息。
    2. 可以将一个或多个特性应用于整个程序集、模块或较小的程序元素(如类和属性)。
    3. 特性可以像方法和属性一样接受自变量。
    4. 程序可使用反射来检查自己的元数据或其他程序中的元数据。 

    2、如何使用特性和声明特性

      2.1 使用特性

        C#语言中内置了许多特性,比如SerializableAttribute、ObsoleteAttribute等,前者标识类可以被序列化,后者标识过时的。.NET有一个约定,所有的特性应该都是以Attribute来结尾,在标记的时候,如果没有加Attribute,编译器会自动寻找带有Attribute的版本,所以在标记的时候我们可以省略Attribute。下面我们使用一下这两个特性。

        [Serializable]
        public class AttributeTest
        {
            [Obsolete("Don't use Old method, use New method.")]
            public void OldMethod()
            {
    
            }
    
            public void NewMethod()
            {
    
            }
        }

        如上代码,标识了[Obsolete]特性的方法,在编译时就会有警告: 'AttributeTest.OldMethod()' is obsolete: 'Don't use Old method, use New method.' 说明该特性是直接影响了编译器的。而标识了[Serializable]特性的对象可以被序列化,是影响了程序的运行。

      2.2 声明特性

        C#提供了System.Attribute类,所有特性类都应改直接活间接继承自System.Attribute类。接下来我们自定义一个特性类。

        public class CustomAttribute : Attribute
        {
            public CustomAttribute()
            {
    
            }
    
            public int Id { get; set; }
            public string Name { get; set; }
            public string Remark { get; set; }
        }

        很简单吧,上面我们就定义了一个特性类,下面我们使用一下自定义的特性。像上面用系统预定义的特性类一样,我们给NewMethod方法加上我们自定义的特性。

        [Serializable]
        public class AttributeTest
        {
            [Obsolete("Don't use Old method, use New method.")]
            public void OldMethod()
            {
    
            }
    
            [Custom(Id = 1, Name = "NewMethod", Remark = "This is a NewMethod.")]
            public void NewMethod()
            {
    
            }
        }  

    3、控制特性的使用

      上面我们说了如何定义和使用特性,但有点小问题,如果我们声明的特性只想标记字段和属性,应该怎么办?同一个特性我们想标记两遍怎么办?带着问题我们继续往下看。

      3.1 AttributeUsage的定义

        AttributeUsage用于描述可以在其中使用特性类的方式。可以F12看一下这个类,它的全名是AttributeUsageAttribute,说明它也是一个特性类,所以简单直白的来说它就是用来描述特性的特性。

      3.2 AttributeUsage的介绍

      它里面有三个属性:

      1. ValidOn:标识指示的属性可应用到的程序元素。默认值是 AttributeTargets.All。
      2. AllowMultiple:指示能否为一个程序元素指定多个指示属性实例。如果为 true,则该特性是可以重复标记的。默认值是 false。
      3. Inherited:指示指示的属性能否由派生类和重写成员继承。如果为 true,则该特性可被派生类继承。默认值是 false。

      3.3AttributeUsage的使用

        介绍了AttributeUsage,下面我们来解决一下开头提的两个问题;如果项目中有不同的需求,可以根据需求来定义。

        [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
        public class CustomAttribute : Attribute
        {
            public CustomAttribute()
            {
    
            }
    
            public int Id { get; set; }
            public string Name { get; set; }
            public string Remark { get; set; }
        }

    4、通过反射获取特性

      看完上面的内容,相信大家都会有些疑惑,我声明了特性,也标记了特性,可它没起什么作用,难道仅仅是为了好看。接下来我们演示如何获取特性,当然,获取到特性后就想做什么都可以啦。

      4.1 获取特性

        特性必须通过反射进行获取、使用。下面代码演示了获取类、方法、属性上的特性,并调用特性方法。

     1         public static void Manager<T>(this T test) where T : AttributeTest
     2         {
     3             Type type = test.GetType();
     4 
     5             // 查找类上的特性
     6             if (type.IsDefined(typeof(CustomAttribute), true))
     7             {
     8                 object[] oAttributeArray = type.GetCustomAttributes(typeof(CustomAttribute), true);
     9                 foreach (CustomAttribute attribute in oAttributeArray)
    10                 {
    11                     attribute.Show();
    12                 }
    13             }
    14 
    15             // 查找属性上的特性
    16             foreach (var prop in type.GetProperties())
    17             {
    18                 if (prop.IsDefined(typeof(CustomAttribute), true))
    19                 {
    20                     object[] oAttributeArrayProp = prop.GetCustomAttributes(typeof(CustomAttribute), true);
    21                     foreach (CustomAttribute attribute in oAttributeArrayProp)
    22                     {
    23                         attribute.Show();
    24                     }
    25                 }
    26             }
    27 
    28             // 查找方法上的特性
    29             foreach (var method in type.GetMethods())
    30             {
    31                 if (method.IsDefined(typeof(CustomAttribute), true))
    32                 {
    33                     object[] oAttributeArrayMethod = method.GetCustomAttributes(typeof(CustomAttribute), true);
    34                     foreach (CustomAttribute attribute in oAttributeArrayMethod)
    35                     {
    36                         attribute.Show();
    37                     }
    38                 }
    39             }
    40 
    41         }

    5、实际应用

      上面说了这么多,可是我还是不会用,咋办呢。下面列出一个实际应用的小栗子。程序中,我们经常会用到枚举,通过枚举值显示文字的时候,通常会if(值){文字},下面我们用特性来获取枚举值对应的文字。

      5.1 准备一个枚举

     1         /// <summary>
     2         /// 用户状态
     3         /// </summary>
     4         public enum UserState
     5         {
     6             /// <summary>
     7             /// 正常状态
     8             /// </summary>
     9             [Remark("正常状态")]
    10             Normal = 0,
    11             /// <summary>
    12             /// 已冻结
    13             /// </summary>
    14             [Remark("已冻结")]
    15             Frozen = 1,
    16             /// <summary>
    17             /// 已删除
    18             /// </summary>
    19             [Remark("已删除")]
    20             Deleted = 2
    21         }

      5.2 显示备注

            public static string GetRemark(this Enum value)
            {
                Type type = value.GetType();
                var field = type.GetField(value.ToString());
                if (field.IsDefined(typeof(RemarkAttribute), true))
                {
                    RemarkAttribute attribute = (RemarkAttribute)field.GetCustomAttribute(typeof(RemarkAttribute), true);
                    return attribute.Remark;
                }
                else
                {
                    return value.ToString();
                }
            }

      用法:

                EnumTest.UserState userState = EnumTest.UserState.Deleted;
                var remark = userState.GetRemark();
                Console.WriteLine(remark);

    6、总结

        特性可以说是无处不在,EF、MVC、WCF、IOC、AOP等等都会用到特性。特性可以在不修改类的情况下对类新增一些功能。

  • 相关阅读:
    网页制作之JavaScript部分3--事件及事件传输方式(函数调用 练习题 )重要---持续更新中
    网页制作之JavaScript部分 2
    网页制作之JavaScript部分 1
    css之display:inline-block与float区别(可以尝试用一下)
    边框圆角化方式(原文链接http://www.cnblogs.com/SJP666/p/4678730.html)
    网页制作之html基础学习5-background-position用法
    网页制作之html基础学习4-格式与布局
    网页制作之html基础学习3-css样式表
    网页制作之html基础学习2-标签
    程序员的成长必备
  • 原文地址:https://www.cnblogs.com/gaozejie/p/10255400.html
Copyright © 2020-2023  润新知