這一篇的內容比較複雜,要注意的地方我都寫成註解,所以我們直接來看相關副程式。我們先來看一個最簡單,也是一般在使用組件的方式。
UseHashtable 副程式
''' <summary>
''' 使用一般 Hashtable 方法來顯示
''' </summary>
Private Sub UseHashtable()
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
UseHashtable 副程式執行結果
一般方式,使用Hashtable 產生Hashtable Hash Count: 1
以上是很一般使用 Hashtable 的方式,沒有任何特別之處。但如果我們是要透過動態程式碼的方式來撰寫,就會複雜很多。
使用動態程式碼撰寫 Hashtable 功能
動態程式碼的撰寫要比較了解物件導向,一個步驟一個頻驟建立出你想要的功能,從型別 --> 建構子 --> 方法 ...。''' <summary>
''' 一般而言,建立動態程式碼是在開發及編譯應用程式階段時,需要載入尚未參考的程式碼。
''' 而非像下例使用的 UseDynamicHashtable 裡的 mscorlib.dll (一般應用程式都會預設載入此組件)
''' 使用動態程式碼,產生 Hashtable,取得及執行add方法、取得Count屬性。
''' 此範例複雜些,請注意註解及參考MSDN各物件說明
''' </summary>
Private Sub UseDynamicHashtable()
Console.WriteLine("使用動態程式產生Hashtable")
Dim path As String = "C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.dll"
Dim asm As Assembly = Assembly.LoadFile(path)
' 取得 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
上面程式碼內容比較多,但看久也會發現「順序」很重要。就是 Step by Step,一、要做什麼;二、要做什麼;…依步驟把內容寫出來。所以說,我們一個封裝很好的 Framework 可以用是非常幸福的事。
UseDynamicHashtable 執行結果
動態程式碼,使用Hashtable
使用動態程式產生Hashtable
取得Hashtable型別
產生建構式
取得Add方法
執行Add方法
取得Count屬性
Hash Count: 1
靜態成員輸出
Hash Count:1
使用動態程式碼,產生 HttpUtility 型別,取得及執行HtmlEncode、HtmlDecode方法
這裡比較難懂,看過上面 UseDynamicHashtable() 之後,我們來看個簡單的。''' <summary>
''' 使用動態程式碼,產生 HttpUtility 型別,取得及執行HtmlEncode、HtmlDecode方法。
''' </summary>
Sub UseDynamicHttpUtility()
Dim path As String = "C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Web.dll"
Dim asm As Assembly = Assembly.LoadFile(path)
' 取得型別
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. .."
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
有沒有簡單點。
UseDynamicHttpUtility 執行結果
動態程式碼, 使用HttpUtility This is Bruce & Sherry's Happy Family. This is Bruce & Sherry's Happy Family. <picture>. This is Bruce & Sherry's Happy Family.
第一行是原始字串。第二行是 HtmlEncode 的結果。第三行是 HtmlDecode 的結果。
結論
簡單整理出動態程式碼有三個步驟:
- 取得型別
- 取得方法
- 使用方法
這一篇所需要的基礎知識比較多,算是比較難的一篇。加油!
- Sytem.Type.GetMethod 方法 (String)
- System.Type.GetMethod 方法 (String, BindingFlags)
- System.Reflection.MethodBase.Invoke 方法 (Object, Object())
- System.Reflection.MethodBase.Invoke 方法 ((Object, BindingFlags, Binder, Object(), CultureInfo)
- Visual Basic - Reflection, 反映教學筆記(1) 前言
- Visual Basic - Reflection, 反映教學筆記(2) 基礎反映了解
- Visual Basic - Reflection, 反映教學筆記(3) 取得特定屬性
- Visual Basic - Reflection, 反映教學筆記(4) 取得型別的4種方法
- Visual Basic - Reflection, 反映教學筆記(5) 取得型別相關屬性
- Visual Basic - Reflection, 反映教學筆記(6) 暸解MethodBody
- Visual Basic - Reflection, 反映教學筆記(7) - BindingFlags 過濾 Member(成員)
沒有留言:
張貼留言
感謝您的留言,如果我的文章你喜歡或對你有幫助,按個「讚」或「分享」它,我會很高興的。