Visual Basic - Reflection, 反映教學筆記(5) 取得型別相關屬性

我們在上一篇「Visual Basic - Reflection, 反映教學筆記(4) 取得型別的4種方法」中,在 Object 取得型別裡,給了一段不算短的程式碼,主要是顯示別型相關訊息。這一篇主要解釋那一段程式碼。此副程式的主要進入點為 ShowTypeAttributes()。

ShowTypeAttributes 副程式

''' <summary>
''' 直接顯示型別相關資訊
''' </summary>
Sub ShowTypeAttributes()
    Dim type As Type = GetType(String)
    ' 取得型別屬性
    GetTypeAttribute(type)
    ' 取得型別自訂屬性
    ShowCustomAttribute(type)
    ' 取得型別 Getxxx 
    ShowTypeGetxxx(type)
End Sub

這裡很簡單,只是取得型別後,我想顯示一些型別的屬性、方法。我把這些方法另外再分為三個小副程式。

GetTypeAttribute 副程式

''' <summary>
''' 由物件取得型別後,額外顯示相關屬性
''' </summary>
''' <param name="type">Type (型別)</param>
Sub GetTypeAttribute(type As Type)
    Console.WriteLine("型別的屬性")
    Console.WriteLine("Assembly : {0}", type.Assembly)
    Console.WriteLine("AQN : {0}", type.AssemblyQualifiedName)
    Console.WriteLine("Attributes: {0}", type.Attributes)
    Console.WriteLine("BaseType: {0}", type.BaseType)
    Console.WriteLine("FullName: {0}", type.FullName)
    Console.WriteLine("HasElementType: {0}", type.HasElementType)
    Console.WriteLine("IsAbstract: {0}", type.IsAbstract)
    Console.WriteLine("IsByRef: {0}", type.IsByRef)
    Console.WriteLine("IsClass: {0}", type.IsClass)
    Console.WriteLine("IsEnum: {0}", type.IsEnum)
    Console.WriteLine("IsGenericType: {0}", type.IsGenericType)
    Console.WriteLine("IsInterface: {0}", type.IsInterface)
    Console.WriteLine("IsMarshalByRef: {0}", type.IsMarshalByRef)
    Console.WriteLine("IsNotPublic: {0}", type.IsNotPublic)
    Console.WriteLine("IsPrimitive: {0}", type.IsPrimitive)
    Console.WriteLine("IsPublic: {0}", type.IsPublic)
    Console.WriteLine("IsSealed: {0}", type.IsSealed)
    Console.WriteLine("IsValueType: {0}", type.IsValueType)
    Console.WriteLine("IsVisible: {0}", type.IsVisible)
    Console.WriteLine("Module: {0}", type.Module)
    Console.WriteLine("Name: {0}", type.Name)
    Console.WriteLine("Namespace: {0}", type.Namespace)
    Console.WriteLine()
    Console.ReadLine()
End Sub

我們列出前一篇文章裡所提到的 Isxxx 屬性,這一類 Isxxx 都是回傳 Boolean 值,我建議打開 MSDN 裡的 System.Type 屬性對照著看,會比較清楚。

ShowCustomAttribute 副程式


''' <summary>
''' 由傳入參數,顯示相關型別相關屬性
''' </summary>
''' <param name="type">Type (型別)</param>
Sub ShowCustomAttribute(type As Type)
    Console.WriteLine("取得類別屬性:")
    For Each attr As Attribute In type.GetCustomAttributes(True)
        Console.WriteLine("  {0}", attr.GetType.Name)
    Next
    Console.WriteLine()
End Sub

這裡注意我們使用的 type.GetCustomAttributes(True) 必須傳入一個 Boolean 值,true 表示要搜尋這個成員的繼承鏈結以尋找屬性,否則為 false。 對於屬性和事件來說,會忽略這個參數。若要搜尋屬性 (Property) 和事件之屬性 (Attribute) 繼承鏈結,請使用 Attribute.GetCustomAttributes 方法的適當多載。

ShowTypeGetxxx 副程式

這裡就精彩了。

ShowTypeGetxxx 又是另一個進入點,然後在裡面分別呼叫其他 7 支副程式,顯示此型別的屬性、巢狀型別、成員、建構子、事件、欄位、方法。

#Region "顯示型別相關 Getxxx 方法"

    ''' <summary>
    ''' 呼叫型別相關 Getxxx 測試方法
    ''' </summary>
    ''' <param name="type">型別 (即Type) 物件</param>
    Sub ShowTypeGetxxx(type As Type)
        ' 顯示型別屬性
        ShowGetProperties(type)
        ' 顯示型別巢狀型別
        ShowGetNestedTypes(type)
        ' 顯示型別成員
        ShowGetMembers(type)
        ' 顯示型別建構子
        ShowGetConstructors(type)
        ' 顯示型別事件
        ShowGetEvent(type)
        ' 顯示型別欄位
        ShowGetFields(type)
        ' 顯示型別方法
        ShowGetMethods(type)
    End Sub

    ''' <summary>
    ''' 簡單測試及顯示型別的屬性(Properties)
    ''' </summary>
    ''' <param name="type">型別 (即Type) 物件</param>
    Private Sub ShowGetProperties(type As Type)
        Console.WriteLine("取得型別Properties")
        For Each pi As PropertyInfo In type.GetProperties
            Console.WriteLine("{0}", pi.Name)
        Next
        Console.WriteLine()
        Console.ReadLine()
    End Sub

    ''' <summary>
    ''' 簡單測試及顯示型別的NestedTypes
    ''' </summary>
    ''' <param name="type">型別 (即Type) 物件</param>
    Private Sub ShowGetNestedTypes(type As Type)
        Console.WriteLine("取得型別NestedTypes")
        For Each gnt As Type In type.GetNestedTypes
            Console.WriteLine("{0}", gnt.Name)
        Next
        Console.WriteLine()
        Console.ReadLine()
    End Sub

    ''' <summary>
    ''' 簡單測試及顯示型別 GetMembers() 方法
    ''' </summary>
    ''' <param name="type">型別 (即Type) 物件</param>
    Private Sub ShowGetMembers(type As Type)
        Console.WriteLine("取得型別Members")
        For Each mi As MemberInfo In type.GetMembers()
            Console.WriteLine("    Member的 Type 及 名稱")
            Console.WriteLine("          {0}:{1}", mi.MemberType, mi.Name)
            ShowMemberType(mi)
        Next
        Console.WriteLine()
        Console.ReadLine()
    End Sub

    ''' <summary>
    ''' 簡單測試及顯示MemberInfo裡MemberType成員,目前只讓 ShowGetMembers 呼叫
    ''' </summary>
    ''' <param name="mi">MemberInfo物件</param>
    Private Sub ShowMemberType(mi As MemberInfo)
        ' MemberInfo 可藉由 MemberTypes 來判斷出型別的不同成員,注意,都是public。
        ' 簡單測試 MemberTypes.Property
        Select Case mi.MemberType
            Case MemberTypes.Constructor
            Case MemberTypes.Custom
            Case MemberTypes.Event
            Case MemberTypes.Field
            Case MemberTypes.Method
            Case MemberTypes.NestedType
            Case MemberTypes.Property
                Dim pi As PropertyInfo = CType(mi, PropertyInfo)
                Console.WriteLine("          Property Type: {0}", pi.PropertyType.Name)
            Case MemberTypes.TypeInfo
            Case MemberTypes.All
            Case Else
                Console.WriteLine("什麼!完全沒有符合的成員!")
        End Select
    End Sub

    ''' <summary>
    ''' 簡單測試及顯示型別 GetConstructors 方法
    ''' </summary>
    ''' <param name="type">型別 (即Type) 物件</param>
    Sub ShowGetConstructors(type As Type)
        Console.WriteLine("取得型別Constructors")
        For Each ci As ConstructorInfo In type.GetConstructors
            Console.WriteLine("    IsSecuritySafeCritical: {0}", ci.IsSecuritySafeCritical)
        Next
        Console.WriteLine()
        Console.ReadLine()
    End Sub

    ''' <summary>
    ''' 簡單測試及顯示型別 GetEvents 方法
    ''' </summary>
    ''' <param name="type">型別 (即Type) 物件</param>
    Sub ShowGetEvent(type As Type)
        Console.WriteLine("取得型別Events")
        For Each ei As EventInfo In type.GetEvents
            Console.WriteLine("    DeclaringType: {0}", ei.DeclaringType)
        Next
        Console.WriteLine()
        Console.ReadLine()
    End Sub

    ''' <summary>
    ''' 簡單測試及顯示型別 GetFields 方法
    ''' </summary>
    ''' <param name="type">型別 (即Type) 物件</param>
    Sub ShowGetFields(type As Type)
        Console.WriteLine("取得型別Fields")
        For Each fi As FieldInfo In type.GetFields
            Console.WriteLine("    FieldType: {0}", fi.FieldType)
        Next
        Console.WriteLine()
        Console.ReadLine()
    End Sub

    ''' <summary>
    ''' 簡單測試及顯示型別 GetMethods 方法
    ''' </summary>
    ''' <param name="type">型別 (即Type) 物件</param>
    Sub ShowGetMethods(type As Type)
        Console.WriteLine("取得型別Methods")
        For Each mi As MethodInfo In type.GetMethods
            Console.WriteLine("Method: {0}, IsPublic: {1}", mi.GetBaseDefinition.Name, mi.IsPublic)
        Next
        Console.WriteLine()
        Console.ReadLine()
    End Sub

#End Region


  • 顯示型別屬性,ShowGetProperties(type)  --> PropertyInfo
  • 顯示型別巢狀型別,ShowGetNestedTypes(type)  --> Type
  • 顯示型別成員,ShowGetMembers(type)  --> MemberInfo
  • 顯示型別建構子,ShowGetConstructors(type)  --> ConstructorInfo
  • 顯示型別事件,ShowGetEvent(type)  --> EventInfo
  • 顯示型別欄位,ShowGetFields(type)  --> FieldInfo
  • 顯示型別方法,ShowGetMethods(type) --> MethodInfo
不知道你有沒有發現,在以上 7 支副程式中,我們都是使用 Info 結尾的類別(除NestedTypes)來接收型別傳過來的資訊。再回去看看以上副程式,雖然很多,但其實動作都是一樣的。你想要「屬性」資訊,那就用 PropertyInfo 來接收資訊,每個你想要的資訊內容都一個對應的 *Info 類別( 請參考 Reflection 類別 ),記住這一點,那以上的副程式看起來比會簡單許多。

參考資料

  1. System.Type 屬性
  2. GetCustomAttributes
  3. Attribute.GetCustomAttributes
  4. Reflection 類別 (以這篇而言,是找 *Info 類別來看)
  5. Visual Basic - Reflection, 反映教學筆記(1) 前言
  6. Visual Basic - Reflection, 反映教學筆記(2) 基礎反映了解
  7. Visual Basic - Reflection, 反映教學筆記(3) 取得特定屬性
  8. Visual Basic - Reflection, 反映教學筆記(4) 取得型別的4種方法

沒有留言:

張貼留言

感謝您的留言,如果我的文章你喜歡或對你有幫助,按個「讚」或「分享」它,我會很高興的。