• 【C#】编写自定义特性与其应用


    特性实质上也是个类,可以有效地将元数据或声明性信息与代码(程序集、类型、方法、属性等)相关联。 将特性与程序实体相关联后,可以在运行时使用反射这项技术查询特性。

    • 直接或间接派生自 Attribute
    • 命名一般以Attribute结尾
    • 必须在类上加AttributeUsage,用于标注当前声明的类应用于哪些对象

    特性定义与关联

    可通过定义特性类创建自己的自定义特性特性类是直接或间接派生自 Attribute 的类,可快速轻松地识别元数据中的特性定义。 假设希望使用编写类型的程序员的姓名来标记该类型。 可能需要定义一个自定义 Author 特性类:

    [System.AttributeUsage(System.AttributeTargets.Class |  
                           System.AttributeTargets.Struct)  
    ]  
    public class AuthorAttribute : System.Attribute  
    {  
        private string name;  
        public double version;  
      
        public AuthorAttribute(string name)  
        {  
            this.name = name;  
            version = 1.0;  
        }  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    类名 AuthorAttribute 是该特性的名称,即 Author 加上 Attribute 后缀。 由于该类派生自 System.Attribute,因此它是一个自定义特性类。 构造函数的参数是自定义特性的位置参数。 在此示例中,name 是位置参数。 所有公共读写字段或属性都是命名参数。 在本例中,version 是唯一的命名参数。 请注意,使用 AttributeUsage 特性可使 Author 特性仅对类和 struct 声明有效。

    可按如下方式使用这一新特性(使用时去掉Attribute,和mvc的Controller类似):

    [Author("P. Ackerman", version = 1.1)]  
    class SampleClass  
    {  
    }
    
    • 1
    • 2
    • 3
    • 4

    AttributeUsage 有一个命名参数 AllowMultiple,通过此命名参数可一次或多次使用自定义特性。 下面的代码示例创建了一个多用特性。

    [System.AttributeUsage(System.AttributeTargets.Class |  
                           System.AttributeTargets.Struct,  
                           AllowMultiple = true)  // 允许多特性
    ]  
    public class AuthorAttribute : System.Attribute
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在下面的代码示例中,某个类应用了同一类型的多个特性。

    [Author("P. Ackerman", version = 1.1)]  
    [Author("R. Koch", version = 1.2)]  
    class SampleClass  
    {  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    应用

    上的例子只是将作者信息的元数据关联到SampleClass 上而已,并没有实际意义的运用,通过使用反射,可以检索通过自定义特性定义的信息。 主要方法是 GetCustomAttributes,它返回对象数组,这些对象在运行时等效于源代码特性。

    现在我们再看下一个使用反射访问特性的一个例子。

    [System.AttributeUsage(System.AttributeTargets.Class |  
                           System.AttributeTargets.Struct,  
                           AllowMultiple = true)  // 允许Author使用多次
    ]  
    
    //为什么上面说命名一般以Attribute结尾,一般就是不是强制性要求。如下命名
    public class Author : System.Attribute  
    {  
        string name;  
        public double version;  
      
        public Author(string name)  
        {  
            this.name = name;  
      
            // 默认值  
            version = 1.0;  
        }  
      
        public string GetName()  
        {  
            return name;  
        }  
    }  
      
    // 类有作者特性
    [Author("P. Ackerman")]  
    public class FirstClass  
    {  
        // ...  
    }  
      
    // 类没有作者特性
    public class SecondClass  
    {  
        // ...  
    }  
      
    // 类有多个作者特性
    [Author("P. Ackerman"), Author("R. Koch", version = 2.0)]  
    public class ThirdClass  
    {  
        // ...  
    }  
      //下面获取类的作者和版本信息并再控制台输出出来(相当于使用了)
    class TestAuthorAttribute  
    {  
        static void Test()  
        {  
            PrintAuthorInfo(typeof(FirstClass));  
            PrintAuthorInfo(typeof(SecondClass));  
            PrintAuthorInfo(typeof(ThirdClass));  
        }  
      
        private static void PrintAuthorInfo(System.Type t)  
        {  
            System.Console.WriteLine("Author information for {0}", t);  
      
            // 使用反射
            System.Attribute[] attrs = System.Attribute.GetCustomAttributes(t);  // 反射.  
      
            // 输出. 
            foreach (System.Attribute attr in attrs)  
            {  
                if (attr is Author)  
                {  
                    Author a = (Author)attr;  
                    System.Console.WriteLine("   {0}, version {1:f}", a.GetName(), a.version);  
                }  
            }  
        }  
    }  
    /* 输出:  
        Author information for FirstClass  
           P. Ackerman, version 1.00  
        Author information for SecondClass  
        Author information for ThirdClass  
           R. Koch, version 2.00  
           P. Ackerman, version 1.00  
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80

    这里还有一个例子大家也可以看看
    C# 自定义特性(Attribute)详解

    参考

    创建自定义特性 (C#)
    使用反射访问特性 (C#)

  • 相关阅读:
    ipv6笔记及总结
    设计模式:快照模式
    7、使用Maven:IDEA环境
    最优控制问题中的折扣因子
    React Hooks为什么要在顶层使用?
    随身WIFI刷真Linux(Debian)系统搭配拓展坞做超低功耗服务器
    小型洗衣机好用吗?最好用的迷你洗衣机
    C语言 —— 操作符
    【C++】纯虚函数和抽象类
    细胞凋亡通路 | MedChemExpress
  • 原文地址:https://blog.csdn.net/weixin_44231544/article/details/127734097