详解C#特性和反射(一)

  使用特性(Attribute)可以将描述程序集的信息和描述程序集中任何类型和成员的信息添加到程序集的元数据和IL代码中,程序可以在运行时通过反射获取到这些信息;

 

  一、通过直接或间接的继承自抽象类System.Attribute可以创建自定义的特性类,自定义的特性类必须声明为公共类,命名一般使用Attribute结尾以保证可读性,自定义特性可以附加到大多数元素声明中,也可以使用特性System.AttributeUsage(该特性只能用于特性类声明)指定该特性所能生效的范围及其它特性特征参数:

[AttributeUsage(AttributeTargets.All, Inherited = true, AllowMultiple = true)]
//其中,枚举组合AttributeTargets指定该特性生效的范围,默认为All即所有范围;
//布尔值Inherited指定应用该特性的成员在派生类中是否会继承该特性,默认为true;
//布尔值AllowMultiple指定能否为同一个元素指定多个此特性,默认为false
public class MyselfAttribute : Attribute { public string ClassName { get; private set; } public string Author; public MyselfAttribute(string className) { this.className = className; } }

  其中特性类的构造函数中的参数称为位置参数(Positional Parameters),类中的其他公共字段和属性称为命名参数(Named Parameter), 通常情况下,将所有必选的参数定义为位置参数,将所有可选的参数定义为命名参数;特性类和普通类一样可以进行构造函数的重载以适应各种情况下初始化参数的组合使用;

 

  二、使用特性时,通过方括号[]将特性名称括起来,并置于使用该特性的元素声明的上方或前方以指定特性,使用时可以省略Attribute后缀,根据想要初始化时调用特性类构造函数的不同,需要将该构造函数所需的参数(即位置参数)的值按照顺序传入,还可以选择是否指定命名参数的值,命名参数的值通过赋值运算符=显式指定:

[Myself("MyClass", Author = "Me")]
//这个声明在概念上等效于: //MyselfAttribute myselfObj = new MyselfAttribute("MyClass"); //myselfObj.Author = "Me"; //[Myself("MyClass", Author = "You")] //特性Myself可以对同一元素指定多次 //也可以将多个特性合并在一个方括号里: //[Myself("MyClass", Author = "Me"), Myself("MyClass", Author = "You")] public class MyClass { public void MyFunc([Myself("MyParameter")]int myNum) //在方法参数列表中给参数指定特性 { //do… } }

   经过编译后,在元数据中查看到的类型定义中的特性信息:

TypeDef #1 (02000002)
-------------------------------------------------------
    TypDefName: MyClass  (02000002)
    Flags     : [Public] [AutoLayout] [Class] [AnsiClass] [BeforeFieldInit]  (00100001)
    Extends   : 01000013 [TypeRef] System.Object
    Method #1 (06000001) 
    -------------------------------------------------------
        MethodName: MyFunc (06000001)
        Flags     : [Public] [Virtual] [HideBySig] [NewSlot]  (000001c6)
        RVA       : 0x00002050
        ImplFlags : [IL] [Managed]  (00000000)
        CallCnvntn: [DEFAULT]
        hasThis 
        ReturnType: Void
        1 Arguments
            Argument #1:  I4
        1 Parameters
            (1) ParamToken : (08000001) Name : myNum flags: [none] (00000000)
            CustomAttribute #1 (0c000003)
            -------------------------------------------------------
                CustomAttribute Type: 06000009
                CustomAttributeName: MyselfAttribute :: instance void .ctor(class System.String)
                Length: 16
                Value : 01 00 0b 4d 79 50 61 72  61 6d 65 74 65 72 00 00 >   MyParameter  <
                ctor args: ("MyParameter")


    Method #2 (06000002) 
    -------------------------------------------------------
        MethodName: .ctor (06000002)
        Flags     : [Public] [HideBySig] [ReuseSlot] [SpecialName] [RTSpecialName] [.ctor]  (00001886)
        RVA       : 0x0000205a
        ImplFlags : [IL] [Managed]  (00000000)
        CallCnvntn: [DEFAULT]
        hasThis 
        ReturnType: Void
        No arguments.

    CustomAttribute #1 (0c000015)
    -------------------------------------------------------
        CustomAttribute Type: 06000009
        CustomAttributeName: MyselfAttribute :: instance void .ctor(class System.String)
        Length: 24
        Value : 01 00 07 4d 79 43 6c 61  73 73 01 00 54 0e 06 41 >   MyClass  T  A<
                      : 75 74 68 6f 72 02 4d 65                          >uthor Me        <
        ctor args: ("MyClass")

  在IL代码中查看到的类型定义中的特性信息:

 

 

  三、系统预定义的一些常用特性:

 

   四、特性通常配合反射起作用,在指定的时机通过反射获得自定义特性并对其进行操作,具体内容在下一章中介绍;

 


如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的认可是我写作的最大动力!

作者:Minotauros
出处:https://www.cnblogs.com/minotauros/

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

 

posted @ 2018-09-20 15:22  Minotauros  阅读(3659)  评论(4编辑  收藏  举报