Visual Basic - Reflection, 反映教學筆記(10) Object-oriented 物件導向範例程式

Class 圖表

我們先看來整個 Class 圖表

圖一:Assembly Object-oriented Class (一) (點擊看大圖)
重點在 SampleFactory,SampleFactory是類別產生工廠。

圖二:Assembly 相關類別 (點擊看大圖)
我們透過一個抽象類別 SuperAssembly 來整理所有的初始化及屬性工作,直接繼承使用。

圖三:Attribute 相關類別(點擊看大圖)
同上,透過抽象類別 SuperAttribute 來整理所有初始化及屬性工作,直接繼承使用。


SuperAssembly.vb 抽象類別

我們先由 SuperAssembly 抽象類別開始,再一層一層看下去。

Imports System.Reflection

''' <summary>
''' 抽象類別,統一進行建構子初始化及屬性條件設定
''' </summary>
''' <remarks></remarks>
Public MustInherit  Class SuperAssembly
    
    Public Property asm() As Assembly
    Public Property assemblyPath() As String

    ' 預設值
    Sub New()
        assemblyPath = "C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.dll"
        asm = Assembly.LoadFile(assemblyPath)
    End Sub

    ' 組件路徑
    Sub New(path As String)
        assemblyPath = path
        asm = Assembly.LoadFile(assemblyPath)
    End Sub

    ' 執行的組件
    Sub new(asm As Assembly )
        Me.asm = asm
    End Sub
End Class

ShowTypeAttributes 類別

Imports System.Reflection

Public Class ShowTypeAttributes
    Inherits SuperAssembly

    ''' <summary>
    ''' 直接顯示型別相關資訊
    ''' </summary>
    Sub Show()
        Dim type As Type = GetType(String)
        ' Sample 5
        GetTypeAttribute(type)
        ' Sample 6
        ShowCustomAttribute(type)
        ' Sample 7
        ShowTypeGetxxx(type)
    End Sub

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

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

#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
End Class

ShowAssemblyInfo 類別

Imports System.Reflection

Public Class ShowAssemblyInfo
    Inherits SuperAssembly 
   
    Sub AssemblyInfo()
        Console.WriteLine("--- Assembly Information ---")
        Console.WriteLine("FullName: {0}", asm.FullName)
        Console.WriteLine("From GAC: {0}", asm.GlobalAssemblyCache)
        Console.WriteLine("Path: {0}", asm.Location)
        Console.WriteLine("Only Reflection: {0}", asm.ReflectionOnly)
        Console.WriteLine("Version: {0}", asm.ImageRuntimeVersion)
        Console.WriteLine("--- 按 Ennter 繼續 ---")
        Console.ReadLine()
    End Sub

    Sub ModuleInfo()
        Dim mods() As [Module] = asm.GetModules
        For Each md As [Module] In mods
            ShowAssemblyModuleBasicInfo(md)
            ShowAssemblyModuleTypesInfo(md)
            ShowAssemblyModuleMethodInfo(md)
            ShowAssemblyModuleFieldInfo(md)
            ShowAssemblyModuleAttributeInfo(md)
            Console.WriteLine("--- 按 Ennter 繼續 ---")
            Console.ReadLine()
        Next
    End Sub

    Private Sub ShowAssemblyModuleBasicInfo(md As [Module])
        Console.WriteLine("--- Module Basic Information ---")
        Console.WriteLine("Name: {0}", md.Name)
        Console.WriteLine("Assembly: {0}", md.Assembly)
        Console.WriteLine("FQN: {0}", md.FullyQualifiedName)
        Console.WriteLine("--- 按 Ennter 繼續 ---")
        Console.ReadLine()
    End Sub

    Private Sub ShowAssemblyModuleTypesInfo(md As [Module])
        Console.WriteLine("--- Module Types Information ---")
        Dim Types() As Type = md.GetTypes()
        For Each type As Type In Types
            Console.WriteLine("Type: {0}", type.Name)
        Next
        Console.WriteLine("--- 按 Ennter 繼續 ---")
        Console.ReadLine()
    End Sub

    Private Sub ShowAssemblyModuleMethodInfo(md As [Module])
        Console.WriteLine("--- Module Method Information")
        Dim methods() As MethodInfo = md.GetMethods()
        For Each mi As MethodInfo In methods
            Console.WriteLine("Method: {0}", mi.Name)
        Next
        Console.WriteLine("--- 按 Ennter 繼續 ---")
        Console.ReadLine()
    End Sub

    Private Sub ShowAssemblyModuleFieldInfo(md As [Module])
        Console.WriteLine("---Module Field Information")
        Dim fields() As FieldInfo = md.GetFields()
        For Each fi As FieldInfo In fields
            Console.WriteLine("Field: {0}", fi.Name)
        Next
        Console.WriteLine("--- 按 Ennter 繼續 ---")
        Console.ReadLine()
    End Sub

    Private Sub ShowAssemblyModuleAttributeInfo(md As [Module])
        Console.WriteLine("--- Module Attribute Information ---")
        Dim gcas() As Object = md.GetCustomAttributes(False)
        For Each gca As Object In gcas
            Console.WriteLine("GetCustomAttribute: {0}", gca.GetType.Name)
        Next
        Console.WriteLine("--- 按 Ennter 繼續 ---")
        Console.ReadLine()
    End Sub

End Class

GetAssemblyType4 類別

Imports System.Reflection

Public Class GetAssemblyType4
    Inherits SuperAssembly

#Region "取得型別的4種方法"

    Sub ShowTypeFromAssembly()
        Dim asmTypes() As Type = asm.GetTypes()
        Console.WriteLine("組件取得:")
        For Each asmType In asmTypes
            Console.WriteLine("Type: {0}", asmType.Name)
        Next
        Console.WriteLine()
        Console.ReadLine()
    End Sub


    Sub ShowTypeFromModule()
        Dim mods() As [Module] = asm.GetModules()
        Dim m As [Module] = mods(0)
        Dim modTypes() As Type = m.GetTypes()

        Console.WriteLine("模組取得:")
        For Each modType In modTypes
            Console.WriteLine("Type: {0}", modType.Name)
        Next
        Console.WriteLine()
        Console.ReadLine()
    End Sub

    Sub ShowTypeFromObject(objArray() As Object)
        For Each obj In objArray
            Dim objType As Type = obj.GetType()
            Console.WriteLine("Object取得:")
            Console.WriteLine("Type: {0}", objType.Name)
            Console.WriteLine()
            
            Dim gatgm As New GetAllTypeGetMethods
            ' 此Show為覆寫版本
            gatgm.Show(objType)
        Next
        Console.WriteLine()
        Console.ReadLine()
    End Sub

    Sub ShowTypeFromVBGetType()
        Dim vbtype As Type = GetType(Int32)
        Console.WriteLine("VB GetType取得:")
        Console.WriteLine("Type: {0}", vbtype.FullName)
        Console.WriteLine()
        Console.ReadLine()
    End Sub
#End Region
End Class

ShowAssemblyInfo 類別

Imports System.Reflection

Public Class ShowAssemblyInfo
    Inherits SuperAssembly 
   
    Sub AssemblyInfo()
        Console.WriteLine("--- Assembly Information ---")
        Console.WriteLine("FullName: {0}", asm.FullName)
        Console.WriteLine("From GAC: {0}", asm.GlobalAssemblyCache)
        Console.WriteLine("Path: {0}", asm.Location)
        Console.WriteLine("Only Reflection: {0}", asm.ReflectionOnly)
        Console.WriteLine("Version: {0}", asm.ImageRuntimeVersion)
        Console.WriteLine("--- 按 Ennter 繼續 ---")
        Console.ReadLine()
    End Sub

    Sub ModuleInfo()
        Dim mods() As [Module] = asm.GetModules
        For Each md As [Module] In mods
            ShowAssemblyModuleBasicInfo(md)
            ShowAssemblyModuleTypesInfo(md)
            ShowAssemblyModuleMethodInfo(md)
            ShowAssemblyModuleFieldInfo(md)
            ShowAssemblyModuleAttributeInfo(md)
            Console.WriteLine("--- 按 Ennter 繼續 ---")
            Console.ReadLine()
        Next
    End Sub

    Private Sub ShowAssemblyModuleBasicInfo(md As [Module])
        Console.WriteLine("--- Module Basic Information ---")
        Console.WriteLine("Name: {0}", md.Name)
        Console.WriteLine("Assembly: {0}", md.Assembly)
        Console.WriteLine("FQN: {0}", md.FullyQualifiedName)
        Console.WriteLine("--- 按 Ennter 繼續 ---")
        Console.ReadLine()
    End Sub

    Private Sub ShowAssemblyModuleTypesInfo(md As [Module])
        Console.WriteLine("--- Module Types Information ---")
        Dim Types() As Type = md.GetTypes()
        For Each type As Type In Types
            Console.WriteLine("Type: {0}", type.Name)
        Next
        Console.WriteLine("--- 按 Ennter 繼續 ---")
        Console.ReadLine()
    End Sub

    Private Sub ShowAssemblyModuleMethodInfo(md As [Module])
        Console.WriteLine("--- Module Method Information")
        Dim methods() As MethodInfo = md.GetMethods()
        For Each mi As MethodInfo In methods
            Console.WriteLine("Method: {0}", mi.Name)
        Next
        Console.WriteLine("--- 按 Ennter 繼續 ---")
        Console.ReadLine()
    End Sub

    Private Sub ShowAssemblyModuleFieldInfo(md As [Module])
        Console.WriteLine("---Module Field Information")
        Dim fields() As FieldInfo = md.GetFields()
        For Each fi As FieldInfo In fields
            Console.WriteLine("Field: {0}", fi.Name)
        Next
        Console.WriteLine("--- 按 Ennter 繼續 ---")
        Console.ReadLine()
    End Sub

    Private Sub ShowAssemblyModuleAttributeInfo(md As [Module])
        Console.WriteLine("--- Module Attribute Information ---")
        Dim gcas() As Object = md.GetCustomAttributes(False)
        For Each gca As Object In gcas
            Console.WriteLine("GetCustomAttribute: {0}", gca.GetType.Name)
        Next
        Console.WriteLine("--- 按 Ennter 繼續 ---")
        Console.ReadLine()
    End Sub
End Class

ShowMemberFilterFlags 類別

Imports System.Reflection

Public Class ShowMemberFilterFlags
    Inherits SuperAssembly

    Public Property flags As BindingFlags 

    ''' <summary>
    ''' 由 BindingFlags 過濾所要取得的成員
    ''' 此測試由固定 String 型別來執行
    ''' </summary>
    Sub ShowString()
        ' 由一般型別來測試
        Console.WriteLine("由GetType(String)取得")
        Dim type As Type = GetType(String)

        ' 設定想要的成員
        ' 重點:可以使用 Or, And … 等使用多個列舉

        Console.WriteLine("BindingFlags條件為:Public、Instance、Static")
        ShowMemberInfo(type.GetMembers(flags))
        Console.WriteLine()
        Console.ReadLine()
    End Sub

    ''' <summary>
    ''' 由 SuperAssembly 定義 asm, assemblyPath,也可自己改變
    ''' </summary>
    Sub ShowAssembly()

        Console.WriteLine(asm.FullName)
        Console.WriteLine()
        Console.ReadLine()

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

        Console.WriteLine()
        Console.ReadLine()
    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 Class

以上就是與 SuperAssembly 抽象類別及繼承類別的程式碼。

SuperAttribute 抽象類別

SuperAttribute 抽象類別,其中最重要的是 Type 屬性,能讓繼承類別能共用。初始化外,還定義一個 Show 方法,且繼承類別必須實作。

''' <summary>
''' 抽象類別,統一進行建構子初始化
''' </summary>
Public MustInherit Class SuperAttribute

    Public Property type() As Type

    ' 預設值
    Sub New()
        type = GetType(System.Int32)
    End Sub

    ' 設定 Type 型別
    Sub New(type As Type)
        Me.type = type
    End Sub

    ''' <summary>
    ''' 每個繼承的類別都必須覆寫Show()
    ''' </summary>
    MustOverride Sub Show()
End Class

GetAllTypeGetMethods 類別

注意,Show 有兩個版本,一個無參數的 Show(),一個是有參數的 Show(type As Type),第二個多載的 Show(type As Type),讓你可以自行傳入型別(Type),然後顯示相關方法、屬性
Imports System.Reflection

Public Class GetAllTypeGetMethods
    Inherits SuperAttribute

    ''' <summary>
    ''' 呼叫型別相關 Getxxx 測試方法
    ''' </summary>
    Overrides Sub Show()
        ShowTypeGetProperties(type)
        ShowTypeGetNestedTypes(type)
        ShowTypeGetMembers(type)
        ShowTypeGetConstructors(type)
        ShowTypeGetEvent(type)
        ShowTypeGetFields(type)
        ShowTypeGetMethods(type)
    End Sub

    ' GetAssemblyType4.ShowTypeFromObject() 需要一個覆寫版本
    Overloads Sub Show(type As Type)
        ShowTypeGetProperties(type)
        ShowTypeGetNestedTypes(type)
        ShowTypeGetMembers(type)
        ShowTypeGetConstructors(type)
        ShowTypeGetEvent(type)
        ShowTypeGetFields(type)
        ShowTypeGetMethods(type)
    End Sub

#Region "測試型別(Type)相關 GetXXX 函式"
    ''' <summary>
    ''' 簡單測試及顯示型別的屬性(Properties)
    ''' </summary>
    ''' <param name="type">型別 (即Type) 物件</param>
    Sub ShowTypeGetProperties(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>
    Sub ShowTypeGetNestedTypes(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>
    Sub ShowTypeGetMembers(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)
            ShowMemberInfo(mi)
        Next
        Console.WriteLine()
        Console.ReadLine()
    End Sub

    ''' <summary>
    ''' 簡單測試及顯示MemberInfo裡MemberType成員,目前只讓 ShowGetMembers 呼叫
    ''' </summary>
    ''' <param name="mi">MemberInfo物件</param>
    Sub ShowMemberInfo(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 ShowTypeGetConstructors(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 ShowTypeGetEvent(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 ShowTypeGetFields(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 ShowTypeGetMethods(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
End Class

GetCustomAttribute 類別

Public Class GetCustomAttribute
    Inherits SuperAttribute 

    Overrides Sub Show()
        Console.WriteLine("取得類別屬性:")
        For Each attr As Attribute In type.GetCustomAttributes(True)
            Console.WriteLine("  {0}", attr.GetType.Name)
        Next
        Console.WriteLine()
    End Sub
End Class

SuperAttribute 抽象類別

Public Class GetTypeAttribute
    Inherits SuperAttribute 

    Overrides Sub Show()
        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
End Class

以上就是 SuperAttribute 抽象類別及繼承的類別,唯一要注意是多載那個地方的使用。

ShowMethodBody

在這裡,你能發現使用Object-oriented(物件導向)比使用副程式彈性多了。

Imports System.Reflection

Public Class ShowMethodBody

    ''' <summary>
    ''' MethodBody提供方法主體之中繼資料和 MSIL 的存取
    ''' </summary>
    Public Sub ShowExample()
        ' GetType(Example):得到類別的型別
        ' GetMethod("MethodBodyExample"):指定得到型別裡的某個方法
        Dim mi As MethodInfo = GetType(Example).GetMethod("MethodBodyExample")
        Dim mb As MethodBody = mi.GetMethodBody()

        ShowMethodBodyInfo(mb)
        Console.WriteLine()
        Console.ReadLine()
    End Sub

    ''' <summary>
    ''' 取得 ShowMethodBody (即自己Self)的 ShowExample 的 MethodBody
    ''' </summary>
    Public Sub ShowSelf()
        Dim mi As MethodInfo = GetType(ShowMethodBody).GetMethod("ShowExample")
        Dim mb As MethodBody = mi.GetMethodBody()

        ShowMethodBodyInfo(mb)
        Console.WriteLine()
        Console.ReadLine()
    End Sub


    ''' <summary>
    ''' 顯示 MethodBody 堆疊大小,區域變數, IL Code
    ''' </summary>
    ''' <param name="mb">方法主體</param>
    Protected Sub ShowMethodBodyInfo(mb As MethodBody)
        Console.WriteLine("取得堆疊大小及區域變數")
        Console.WriteLine("MaxStack: {0}", mb.MaxStackSize)
        For Each local As LocalVariableInfo In mb.LocalVariables
            Console.WriteLine("Local Var ({0}) : {1}", local.LocalType, local.LocalIndex)
        Next
        Console.WriteLine()

        Console.WriteLine("取得IL程式碼")
        For Each b As Byte In mb.GetILAsByteArray()
            Console.Write("{0:x2}", b)
        Next
    End Sub
End Class

在之前濕透了的範例中,因為都是副程式,所以我們複製了一個 MSDN 範例 Class,才有辦法讓程式順利運作,但在這裡,如我們的 ShowSelf() 一樣,類別多的是,想怎麼用都行

DynamicCode 類別

注意最前面二行的註解即可,我們讓函式自己決定要載入的組件,其他一樣。

Imports System.Reflection

Public Class DynamicCode

    ' 因為我們 assemblyPath 及 asm 必須固定,以防錯誤,不去繼承 SuperAssembly 來使用。
    ' 且不許使用者來修改,所以為 Private
    Private Property asm() As Assembly
    Private Property assemblyPath() As String

    Sub new()

    End Sub

    ''' <summary>
    ''' 使用一般 Hashtable 方法來顯示
    ''' </summary>
    Sub GeneralHashtable()
        Console.WriteLine("產生Hashtable")
        Dim tb As New Hashtable()
        tb.Add("Hi", "Hello")
        Console.WriteLine("Hash Count: {0}", tb.Count)
        Console.WriteLine()
        Console.ReadLine()
    End Sub

    ''' <summary>
    ''' 一般而言,建立動態程式碼是在開發及編譯應用程式階段時,需要載入尚未參考的程式碼。
    ''' 而非像下例使用的 UseDynamicHashtable 裡的 mscorlib.dll (一般應用程式都會預設載入此組件)
    ''' 使用動態程式碼,產生 Hashtable,取得及執行add方法、取得Count屬性。
    ''' 此範例複雜些,請注意註解及參考MSDN各物件說明
    ''' </summary>
    Sub DynamicHashtable()
        Console.WriteLine("使用動態程式產生Hashtable")

        assemblyPath = "C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.dll"
        asm = Assembly.LoadFile(assemblyPath)

        ' 取得 Hashtable 型別, 注意下面ci取得建構式
        Console.WriteLine(" 取得Hashtable型別")
        Dim hashType As Type = asm.GetType("System.Collections.Hashtable")

        Console.WriteLine("     產生建構式")
        Dim argType() As Type = Type.EmptyTypes
        ' 用 ConstructorInfo 來建構這個新型別
        ' Type.GetConstructor(...),有三個多載,我們使用第一個來測試
        ' GetConstructor(Type()),搜尋其參數符合在指定陣列中(Type())的型別的公用執行個體建構函式。 
        ' 我們傳入一個「空的型別陣列」 argType()
        Dim ci As ConstructorInfo = hashType.GetConstructor(argType)
        ' 呼叫Invoke,產生一個空物件,即一個空的 Hashtable
        Dim newHash As Object = ci.Invoke(New Object() {})

        '' --- 這是另一種寫法 ---
        '' --- 我們傳入一個含Int32型別的陣列 ---
        'Dim argTypes() As Type = New Type() {GetType(System.Int32)}
        'Dim ci As ConstructorInfo = hashType.GetConstructor(argTypes)
        '' --- 注意,因為我們傳入的型別陣列為 Int32,所以產生物件時必須給一個 Int32 值---
        '' --- 值可以隨便給,只要是在符合 Int32 範圍即可 ---
        'Dim newHash As Object = ci.Invoke(New Object() {1024})

        Console.WriteLine("     取得Add方法")
        ' 取得型別方法
        Dim mi As MethodInfo = hashType.GetMethod("Add")
        Console.WriteLine("     執行Add方法")
        ' 執行取得的方法
        ' Public Function Invoke ( obj As Object, parameters As Object() ) As Object
        ' obj:物件,要在其上叫用方法或建構函式。
        ' parameters:叫用方法或建構函式的引數清單。
        ' 我要執行 newHash 物件(Hashtable) 的 add 方法,參數是 "Hi", "Hello"
        mi.Invoke(newHash, New Object() {"Hi", "Hello"})

        Console.WriteLine("     取得Count屬性")
        ' 取得Count屬性
        Dim pi As PropertyInfo = hashType.GetProperty("Count")
        ' Public Overridable Function GetValue ( obj As Object, index As Object() ) As Object
        ' obj:其屬性值將被傳回的物件。
        ' index:索引屬性的選擇性索引值。非索引屬性的這個值應為 Nothing。
        ' 取出 Count 值
        Dim count As Integer = CType(pi.GetValue(newHash, Nothing), Integer)

        Console.WriteLine("Hash Count: {0}", count)
        Console.WriteLine()

        Console.WriteLine("靜態成員輸出")
        ' 使用靜態成員
        Dim consoleType As Type = GetType(Console)
        ' 注意,我們傳入的型別陣列的型別是String
        Dim WriteLineMeth As MethodInfo = consoleType.GetMethod("WriteLine", New Type() {GetType(String)})
        ' 靜態成員可以不需要建立一個物件,傳入 Nothing
        ' 型別陣列的型別是String,count.ToString()
        WriteLineMeth.Invoke(Nothing, New Object() {"Hash Count:" & count.ToString()})

        ' 如果我們傳入的型別陣列的型別是Int32
        'Dim WriteLineMeth As MethodInfo = consoleType.GetMethod("WriteLine", New Type() {GetType(Int32)})
        ' 型別陣列的型別是Int32,count (Integer) 直接輸出即可
        'WriteLineMeth.Invoke(Nothing, New Object() {count})
    End Sub

    ''' <summary>
    ''' 使用動態程式碼,產生 HttpUtility 型別,取得及執行HtmlEncode、HtmlDecode方法。
    ''' </summary>
    Sub DynamicHttpUtility()
        assemblyPath = "C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Web.dll"
        asm = Assembly.LoadFile(assemblyPath)
        ' 取得型別
        Dim utilType As Type = asm.GetType("System.Web.HttpUtility")

        ' 重點一
        ' 取得方法
        Dim encode As MethodInfo = utilType.GetMethod("HtmlEncode", New Type() {GetType(System.String)})
        Dim decode As MethodInfo = utilType.GetMethod("HtmlDecode", New Type() {GetType(System.String)})

        Dim oStr As String = "This is Bruce & Sherry's Happy Family. <picture>."
        Console.WriteLine(oStr)

        ' 重點二
        ' 使用方法
        Dim encoded As String = CType(encode.Invoke(Nothing, New Object() {oStr}), String)
        Console.WriteLine(encoded)

        Dim decoded As String = CType(decode.Invoke(Nothing, New Object() {encoded}), String)
        Console.WriteLine(decoded)

        Console.Read()
    End Sub
End Class

RunTimeCreateAssembly 類別

我們新增兩個屬性,讓使用者可以自己決定組件名稱和組件版本。唯一注意,組件版本必須使用 New Version("x.x.x.x") 來給值。絕大部份是使用 Emit 類別。

Imports System.Reflection
Imports System.Reflection.Emit

Public Class RunTimeCreateAssembly
    
    ' 組件名稱
    Public Property AssemblyName() As String 
    ' 組件版本,必須使用 New Version("x.x.x.x") 來給值
    Public Property AssemblyVersion() As Version  

    ''' <summary>
    ''' 建立動態組件
    ''' </summary>
    Sub Create()
        ' 1. 建立組件
        Console.WriteLine("定義組件")
        Dim tempName As New AssemblyName()
        tempName.Name = AssemblyName
        tempName.Version = AssemblyVersion

        ' 使用 DefineDynamicAssembly 動態產生組件
        Dim AssemBL As AssemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(tempName, AssemblyBuilderAccess.RunAndSave)

        ' 2. 建立模組
        Console.WriteLine("定義模組")
        ' DefineDynamicModule 動態產生模組
        ' 如果要建立一個單一檔案的組件,並將此組件序列化在磁碟之中,最後的Save名稱必須與以下DefineDynamicModule裡名稱相同。
        Dim ModuleBL As ModuleBuilder = AssemBL.DefineDynamicModule(tempName.Name, tempName.Name & ".dll")

        ' 3. 建立型別
        Console.WriteLine("定義型別")
        ' DefineType 動態產生型別
        Dim BruceType As TypeBuilder = ModuleBL.DefineType("KKBruceType", TypeAttributes.Class Or TypeAttributes.Public)
        ' 指定父類別及介面給DefineType
        'Dim tb As TypeBuilder = mb.DefineType("KKBruceMyNewType", TypeAttributes.Class Or TypeAttributes.Public,
        '                                      GetType(Hashtable),
        '                                      New Type() {GetType(IDisposable)})


        ' 4. 建立成員
        Console.WriteLine("定義相關成員")
        ' 4.1 建立建構子
        Console.WriteLine("     定義建構子")
        ' MethodAttributes代表建構子的類型
        'Dim ConstructorBL As ConstructorBuilder = BruceType.DefineDefaultConstructor(MethodAttributes.Public)

        ' 4.2 利用ConstructorBuilder建立ILGenerator物件

        ' --- 註:執行會產生錯誤 ---
        ' --- 註:依MSDN查詢:Runtime 會為預設建構函式產生程式碼。因此,如果嘗試取得 ILGenerator,則會擲回例外狀況。 ---

        'Console.WriteLine("     建立ILGenerator物件")

        ' ILGenerator 可產生 Microsoft Intermediate Language (MSIL) 指令。
        'Dim codeGen As ILGenerator = ConstructorBL.GetILGenerator()

        ' Emit:多載。放置指令到 Just-In-Time (JIT) 編譯器的 Microsoft Intermediate Language (MSIL) 資料流中。
        ' OpCodes 類別:提供 Microsoft Intermediate Language (MSIL) 指令的欄位表示,以用於 ILGenerator 類別成員 (例如 Emit) 的發出。
        ' Ret欄位:從目前方法傳回,將被呼叫端評估堆疊的傳回值 (如果有的話) 推入至呼叫端的評估堆疊。 
        'codeGen.Emit(OpCodes.Ret)

        ' 4.3 建立方法
        Console.WriteLine("     定義方法")
        Dim MethodBLOne As MethodBuilder = BruceType.DefineMethod("AddStringOne", MethodAttributes.Public, Nothing, New Type() {GetType(String)})
        ' 第三個參數:建新新方法的回傳型別
        ' 第四個參數:參數型別
        Dim MethodBLTwo As MethodBuilder = BruceType.DefineMethod("AddStringTwo", MethodAttributes.Public Or MethodAttributes.Static,
                                                     Nothing,
                                                     New Type() {GetType(String)})

        ' 4.4 建立私有欄位
        Console.WriteLine("     定義私有欄位")
        Dim FieldBL As FieldBuilder = BruceType.DefineField("_count", GetType(Int32), FieldAttributes.Private)

        ' 4.5 建立屬性
        Console.WriteLine("     定義屬性")
        ' PropertyAttributes.None 列舉常數不能定義所有的屬性
        Dim PropertyBL As PropertyBuilder = BruceType.DefineProperty("Count", PropertyAttributes.None, GetType(Int32), Type.EmptyTypes)

        ' 4.6 在方法中定義設得或設定屬性值
        Console.WriteLine("     定義方法中設得或設定屬性值")
        ' 注意,使用MethodAttributes
        Dim getMethodAttributes As MethodAttributes = MethodAttributes.Public Or
                                                MethodAttributes.SpecialName Or
                                                MethodAttributes.HideBySig

        Dim propGet As MethodBuilder = BruceType.DefineMethod("get_Count", getMethodAttributes, GetType(Int32), Type.EmptyTypes)
        ' 讓方法可以設定與取得屬性值
        PropertyBL.SetGetMethod(propGet)

        ' 5. 建立型別
        Console.WriteLine("產生新型別")

        Console.WriteLine(" 產生所有方法的ILGenerator")
        ' --- 超重要 ---
        ' --- 請參考方法 summary ---
        RunMethodBLGetILGenerator(MethodBLOne)
        RunMethodBLGetILGenerator(MethodBLTwo)
        RunMethodBLGetILGenerator(propGet)

        Console.Write(" 產生型別")
        Dim KKBruceType As Type = BruceType.CreateType()

        ' 5.1 顯示此型別方法
        Console.WriteLine()
        Console.WriteLine("     顯示型別方法(注意我們產生動態產生的方法)")
        GetRunTimeAssemblyMethods(KKBruceType)
        Console.WriteLine()
        Console.ReadLine()

        ' 6. 儲存組件到磁碟中
        Console.WriteLine("儲存組件到磁碟中...")
        ' 一但被寫入到磁碟中,任何程式都可以載入這個組件使用。
        AssemBL.Save(tempName.Name & ".dll")
        Console.WriteLine("儲存完成。(請""開啟專案目錄""下「\bin\Debug」查看產生的動態組件 " & tempName.Name & ".dll")
        Console.ReadLine()
    End Sub

    ''' <summary>
    ''' 傳回這個方法的 ILGenerator
    ''' </summary>
    ''' <param name="methodInstance">MethodBuilder 的執行個體</param>
    ''' <remarks>
    ''' 建立型別之前要為所有 MethodBuilder 執行 GetILGenerator()。
    ''' 不然會產生一個「方法 'xxx' 沒有方法主體。」的錯誤,這裡 Debug 花了我好久!XD!
    ''' 參考:http://msdn.microsoft.com/zh-tw/library/system.reflection.emit.methodbuilder.definegenericparameters%28VS.85%29.aspx 範例才找出解法
    ''' </remarks>
    Private Sub RunMethodBLGetILGenerator(methodInstance As MethodBuilder)
        ' MethodBuilder.GetILGenerator()
        ' 傳回這個方法的 ILGenerator,使用預設 Microsoft Intermediate Language (MSIL) 資料流的 64 位元大小。 
        Dim ilgen As ILGenerator = methodInstance.GetILGenerator()
        ilgen.Emit(OpCodes.Ldnull)
        ilgen.Emit(OpCodes.Ret)
    End Sub

    ''' <summary>
    ''' 取得動態組件方法屬性
    ''' </summary>
    ''' <param name="KKBruceType">型別</param>
    Private Sub GetRunTimeAssemblyMethods(ByVal KKBruceType As Type)
        Console.WriteLine("     Full Name: {0}", KKBruceType.FullName)
        For Each m As MemberInfo In KKBruceType.GetMethods()
            Console.WriteLine("         Member({0}):{1}", m.MemberType, m.Name)
        Next
    End Sub
End Class

這邊你也能學我,寫個抽象類別,去統一建構子及屬性,在建構子裡給屬性初始值,預設程式的錯誤。前面我已經寫了二個例子,這一個我就不改寫了,留給各位當練習題。

SampleFactory 類別

工廠終於來了,沒有工廠就沒有實體!!!

''' <summary>
''' 簡單工廠模式
''' </summary>
Public Class SampleFactory
    Public Shared Function Create(sampleName As String) As Object
        Dim SampleObject As Object = Nothing
        Select Case sampleName
            Case "Sample1"
                SampleObject = New ShowAssemblyInfo()
            Case "Sample2"
                SampleObject = New ShowAttributeInfo()
            Case "Sample3"
                SampleObject = New GetAssemblyType4()
            Case "Sample4"
                SampleObject = New ShowTypeAttributes()
            Case "Sample5"
                SampleObject = New ShowMethodBody()
            Case "Sample6"
                SampleObject = New ShowMemberFilterFlags()
            Case "Sample7"
                SampleObject = New DynamicCode()
            Case "Sample8"
                SampleObject = New RunTimeCreateAssembly()
        End Select

        Return SampleObject
    End Function
End Class

依傳入的關鍵字來建立及回傳相對應的實體。

Module1.vb 主程式

一樣的選擇題小遊戲,注意,實體化是透過工廠「SampleFactory.Create()」,而且透過屬性取給值非常方便。
Module Module1

    Sub Main()

        Dim flags As Boolean = True
        Dim selectNumber As Integer = 0

        While flags

            If flags = True Then
                If selectNumber >= 0 AndAlso selectNumber <= 8 Then
                    Console.WriteLine("請輸入想執行的範例(0為結束),輸入完請按 Enter。")
                    Console.Write("請輸入 1 ~ 8 (預設1):")
                    Try
                        selectNumber = Console.ReadLine()
                    Catch ex As Exception
                        ' 如果使用者未輸入按 Enter,會引發錯誤!
                        Console.WriteLine("未輸入,本程式將結束 ...")
                        selectNumber = 0
                    End Try
                Else
                    Console.WriteLine("本程式將結束 ...")
                    selectNumber = 0
                End If
            End If

            Select Case selectNumber
                Case 0
                    flags = False
                    Console.WriteLine("請按 Enter 結束本程式.")
                Case 1
                    Console.WriteLine()
                    Console.WriteLine("Sample 1")
                    Console.WriteLine("")

                    ' ----------------------------------
                    ' ShowAssemblyInfo.vb 測試
                    ' ----------------------------------

                    Dim Sample1 As ShowAssemblyInfo = SampleFactory.Create("Sample1")
                    Sample1.AssemblyInfo()
                    Sample1.ModuleInfo()

                    Console.WriteLine("---改變組件路徑---")
                    Console.ReadLine()

                    ' 這裡可以改成讓使用者自己輸入
                    Sample1.assemblyPath = "C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Drawing.dll"
                    Sample1.asm = System.Reflection.Assembly.LoadFile(Sample1.assemblyPath)
                    Sample1.AssemblyInfo()
                    Sample1.ModuleInfo()

                    Console.WriteLine()
                    Console.WriteLine("---載入正在執行的組件---")
                    Console.ReadLine()

                    Sample1.asm = System.Reflection.Assembly.GetExecutingAssembly
                    Sample1.AssemblyInfo()
                    Sample1.ModuleInfo()
                    Console.WriteLine()
                    Console.WriteLine("Sample 1 結束.")
                    Console.WriteLine()
                Case 2
                    Console.WriteLine()
                    Console.WriteLine(" Sample 2")
                    Console.WriteLine()
                    ' ----------------------------------
                    ' ShowAttributeInfo.vb 測試
                    ' 請參考 My Project\AssemblyInfo.vb 裡的屬性。
                    ' ----------------------------------

                    Dim Sample2 As ShowAttributeInfo = SampleFactory.Create("Sample2")
                    Sample2.ShowAttributeInfo()

                    Sample2.assemblyPath = "C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Drawing.dll"
                    Sample2.ShowAttributeInfo()

                    Sample2.asm = System.Reflection.Assembly.GetExecutingAssembly
                    Sample2.ShowAttributeInfo()

                    Console.WriteLine()
                    Console.WriteLine("Sample 2 結束.")
                    Console.WriteLine()
                Case 3
                    Console.WriteLine()
                    Console.WriteLine("Sample 3")
                    Console.WriteLine("請參考 My Project\AssemblyInfo.vb 裡的屬性。")
                    Console.WriteLine()

                    ' ----------------------------------
                    ' ShowAttributeInfo.vb 測試
                    ' 請參考 My Project\AssemblyInfo.vb 裡的屬性。
                    ' ----------------------------------

                    Dim Sample3 As GetAssemblyType4 = SampleFactory.Create("Sample3")
                    Sample3.ShowTypeFromAssembly()
                    Sample3.ShowTypeFromModule()

                    Sample3.assemblyPath = "c:\windows\microsoft.net\framework\v4.0.30319\system.drawing.dll"
                    Sample3.ShowTypeFromAssembly()
                    Sample3.ShowTypeFromModule()

                    Sample3.asm = System.Reflection.Assembly.GetExecutingAssembly()
                    Sample3.ShowTypeFromAssembly()
                    Sample3.ShowTypeFromModule()

                    ' string, int32, double, boolean
                    Dim t() As Object = {"string", 1, 0.5, True}
                    Sample3.ShowTypeFromObject(t)

                    Sample3.ShowTypeFromVBGetType()

                    Console.WriteLine()
                    Console.WriteLine("Sample 3 結束.")
                    Console.WriteLine()
                Case 4
                    Console.WriteLine()
                    Console.WriteLine("Sample 4")
                    Console.WriteLine()

                    ' ----------------------------------
                    ' 1. 使用型別
                    ' 2. 取得型別類別屬性
                    ' 3. 取得型別物件
                    ' ----------------------------------

                    Dim Sample4 As ShowTypeAttributes = SampleFactory.Create("Sample4")
                    Sample4.Show()

                    Console.WriteLine()
                    Console.WriteLine("Sample 4 結束.")
                    Console.WriteLine()
                Case 5
                    Console.WriteLine()
                    Console.WriteLine("Sample 5")
                    Console.WriteLine()

                    ' ----------------------------------
                    ' Example 類別,請參考:http://msdn.microsoft.com/zh-tw/library/system.reflection.methodbody.aspx
                    ' ----------------------------------

                    Dim Sample5 As ShowMethodBody = SampleFactory.Create("Sample5")
                    ' 使用 MSDN Example Class
                    Sample5.ShowExample()
                    ' 使用 ShowMethodBody Class
                    Sample5.ShowSelf()

                    Console.WriteLine()
                    Console.WriteLine("Sample 5 結束.")
                    Console.WriteLine()
                Case 6
                    Console.WriteLine()
                    Console.WriteLine("Sample 6")
                    Console.WriteLine()

                    ' ----------------------------------
                    ' BindingFlags 取得特定成員
                    ' ----------------------------------

                    Dim Sample6 As ShowMemberFilterFlags = SampleFactory.Create("Sample6")
                    ' 設定 ShowString 使用 flags
                    Sample6.flags = System.Reflection.BindingFlags.Public Or
                                     System.Reflection.BindingFlags.Instance Or
                                     System.Reflection.BindingFlags.Static

                    Sample6.ShowString()

                    ' 預設建構子裡的 Assembly 
                    ' 設定 ShowAssembly 使用 flags
                    Sample6.flags = System.Reflection.BindingFlags.DeclaredOnly Or
                                    System.Reflection.BindingFlags.Public Or
                                    System.Reflection.BindingFlags.Instance

                    Sample6.ShowAssembly()

                    ' 現在正在執行的 Assembly
                    Sample6.asm = System.Reflection.Assembly.GetExecutingAssembly()
                    Sample6.ShowAssembly()

                    ' 指定 ShowAssembly 條件
                    Sample6.assemblyPath = "C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.ServiceProcess.dll"
                    Sample6.asm = System.Reflection.Assembly.LoadFile(Sample6.assemblyPath)
                    Sample6.ShowAssembly()

                    Console.WriteLine()
                    Console.WriteLine("Sample 6 結束.")
                    Console.WriteLine()
                Case 7
                    Console.WriteLine()
                    Console.WriteLine("Sample 7")
                    Console.WriteLine()

                    ' ----------------------------------
                    ' 動態程式碼
                    ' ----------------------------------

                    Dim Sample7 As DynamicCode = SampleFactory.Create("Sample7")
                    Sample7.GeneralHashtable()
                    Sample7.DynamicHashtable()
                    Sample7.DynamicHttpUtility()

                    Console.WriteLine()
                    Console.WriteLine("Sample 7 結束.")
                    Console.WriteLine()
                Case 8
                    Console.WriteLine()
                    Console.WriteLine("Sample 8")

                    ' ----------------------------------
                    ' 執行環境中產生程式碼
                    ' ----------------------------------
                    Dim Sample8 As RunTimeCreateAssembly = SampleFactory.Create("Sample8")
                    ' 先指定要產生組件名稱及版本
                    Sample8.AssemblyName = "KKBruceSample8Assembly"
                    Sample8.AssemblyVersion = New Version("1.1.1.1")
                    Sample8.Create()

                    Console.WriteLine()
                    Console.WriteLine("Sample 8 結束.")
                    Console.WriteLine()
                Case Else
                    Console.WriteLine("輸入數字錯誤!")
            End Select
        End While

        Console.ReadLine()
    End Sub
End Module

最後一個 Sample8,各位試著動手改寫為抽象類別,然後在不給組件名稱和版本的情況下,去執行,讓你的建構子去給預設值。

結論

在 MSDN 之中,有很大一部分在討論「泛型」的 Reflection,不過我自認為理解層度不足,等有一天讓我看懂了,或有"通"的感覺,我再來分享。經過前九篇的教學筆記,應該想要看懂大部分 Reflecion 程式碼應該不是問題。

另外,撰寫這第十篇 Reflection,我真的認為「重構」這本書實在很不簡單,把平常又重要的事情整理出一套系統化方法,讓我們可以有效學習,程式人員必需人手一本的書,不管你寫不寫物件導向,只要是有在寫程式,你就必須一讀。

濕、乾二重奏 - 下載原始專案檔

檔案內容包含濕透了 AssemblyDemo 專案(即第九篇的檔案),烘乾的 AssemblyDemoOO 專案。


解壓縮密碼:KKBruce

參考資料

沒有留言:

張貼留言

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