Visual Basic - Reflection, 反映教學筆記(7) - BindingFlags 過濾 Member(成員)

我們再談談Type 的 Member,我們前面寫過一段簡單取得 Member 的程式碼:

''' <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

基本上,這沒什麼問題。但如果我想的資訊只需要「特定成員呢?」這時候我們就必須設定一個 BindingFlags 列舉型別給 type.GetMembers(),BindingFlags 指定控制繫結的旗標和由反映為引導的成員和型別搜尋方式。

這些 BindingFlags 會控制在叫用 (Invoke)、建立、取得、設定和尋找成員和型別的 System、System.Reflection 和 System.Runtime 命名空間中眾多類別的繫結。 

BindingFlags 用於下列 Type 方法和其他地方,例如,

  • MethodBase.Invoke
  • GetMembers 
  • GetEvents 
  • InvokeMember 
  • Activator.CreateInstance 
  • GetConstructor 
  • GetConstructors 
  • GetMethod 
  • GetMethods 
  • GetField 
  • GetFields 
  • GetEvent 
  • GetProperty 
  • GetProperties 
  • GetMember 
  • FindMembers 

其中 InvokeMember 和 GetMethod 特別重要。


ShowMemberFilterFlags 副程式

#Region "顯示Member方法,但使用 BindingFlags 過濾成員"
    ''' <summary>
    ''' 由 BindingFlags 過濾所要取得的成員,你可以改變bfs1,2後面的參數來觀察
    ''' </summary>
    Private Sub ShowMemberFilterFlags()
        ' 由一般型別來測試
        Console.WriteLine("由GetType(String)取得")
        Dim t As Type = GetType(String)

        ' 設定想要的成員
        ' 重點:可以使用 Or, And … 等使用多個列舉
        Dim bfs1 As BindingFlags = BindingFlags.Public Or
                                     BindingFlags.Instance Or
                                     BindingFlags.Static

        Console.WriteLine("BindingFlags條件為:Public、Instance、Static")
        ShowMemberInfo(t.GetMembers(bfs1))
        Console.WriteLine()
        Console.ReadLine()

        ' 由載入組件來測試
        Console.WriteLine("由System.ServiceProcess.dll載入組件")
        Dim path As String = "C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.ServiceProcess.dll"
        Dim asm As Assembly = Assembly.LoadFrom(path)

        Dim bfs2 As BindingFlags = BindingFlags.DeclaredOnly Or
                                     BindingFlags.Public Or
                                     BindingFlags.Instance

        Console.WriteLine(asm.FullName)
        ' 停一下,不然看不到資訊,太長了
        Console.ReadLine()

        Console.WriteLine()
        Dim types() As Type = asm.GetTypes()
        For Each type As Type In types
            Console.WriteLine("Type:{0}", type.Name)
            Console.WriteLine("     BindingFlags條件為:DeclaredOnly、Public、Instance")
            ShowMemberInfo(type.GetMembers(bfs2))
        Next
    End Sub

    ''' <summary>
    ''' 顯示 MemberInfo 物件相關資訊
    ''' </summary>
    ''' <param name="mi">MemberInfo 陣列物件</param>
    ''' <remarks></remarks>
    Private Sub ShowMemberInfo(mi() As MemberInfo)
        For Each m As MemberInfo In mi
            Console.WriteLine("         Member: {0}, Type: {1}", m.Name, m.MemberType)
        Next
    End Sub
#End Region

我們執行兩次,兩次給的 BindingFlags 不一樣,你可以自由改變載入的 Type 和 BindingFlags 去測試看看。然後透過 ShowMemberInfo() 來顯示成員名稱及成員型別。

ShowMemberFilterFlags 副程式執行結果

先由內建型別開始,我們指定為 String 型別。

由GetType(String)取得
BindingFlags條件為:Public、Instance、Static
         Member: Join, Type: Method
         Member: Equals, Type: Method
         Member: op_Equality, Type: Method
         Member: op_Inequality, Type: Method
         Member: get_Chars, Type: Method
         Member: CopyTo, Type: Method
         Member: ToCharArray, Type: Method
         Member: IsNullOrEmpty, Type: Method
         Member: IsNullOrWhiteSpace, Type: Method
         Member: GetHashCode, Type: Method
         Member: get_Length, Type: Method
         Member: Split, Type: Method
         Member: Substring, Type: Method
         Member: Trim, Type: Method
         Member: TrimStart, Type: Method
         Member: TrimEnd, Type: Method
         Member: IsNormalized, Type: Method
         Member: Normalize, Type: Method
         Member: Compare, Type: Method
         ... 略 ...

以上結果是整理過的內容,不然你應該看到很多重覆內容的才對,原因很簡單,例如 String.Join() 它的重載就有五個之多,所以你會看到五次「Member: Join, Type: Method」才對。

載入一個已存在的組件,來測試看看。

由System.ServiceProcess.dll載入組件
System.ServiceProcess, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
... 略,以下為最後五筆 ...
Type:DeferredHandlerDelegate
     BindingFlags條件為:DeclaredOnly、Public、Instance
         Member: Invoke, Type: Method
         Member: BeginInvoke, Type: Method
         Member: EndInvoke, Type: Method
         Member: .ctor, Type: Constructor
Type:DeferredHandlerDelegateCommand
     BindingFlags條件為:DeclaredOnly、Public、Instance
         Member: Invoke, Type: Method
         Member: BeginInvoke, Type: Method
         Member: EndInvoke, Type: Method
         Member: .ctor, Type: Constructor
Type:DeferredHandlerDelegateAdvanced
     BindingFlags條件為:DeclaredOnly、Public、Instance
         Member: Invoke, Type: Method
         Member: BeginInvoke, Type: Method
         Member: EndInvoke, Type: Method
         Member: .ctor, Type: Constructor
Type:UnsafeNativeMethods
     BindingFlags條件為:DeclaredOnly、Public、Instance
Type:ServiceNameConverter
     BindingFlags條件為:DeclaredOnly、Public、Instance
         Member: CanConvertFrom, Type: Method
         Member: ConvertFrom, Type: Method
         Member: GetStandardValues, Type: Method
         Member: GetStandardValuesExclusive, Type: Method
         Member: GetStandardValuesSupported, Type: Method
         Member: .ctor, Type: Constructor

這邊我們只要了解,我們可以使用 BindingFlags 來改變我們搜尋出來的結果即可,細部的舉列值,請參考 MSDN。

參考資料

沒有留言:

張貼留言

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