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

Minotauros發表於2018-09-20

  使用特性(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/

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連線,否則保留追究法律責任的權利。

 

相關文章