轉(zhuǎn)帖|其它|編輯:郝浩|2010-06-17 11:54:05.000|閱讀 829 次
概述:如果用戶需要的是Windows.Forms里面的數(shù)十種控件,那么你的Select語(yǔ)句也要寫數(shù)十行嗎?若有一種方法能夠在運(yùn)行時(shí)任意指定對(duì)象的創(chuàng)建類型,甚至是用表示類型的名字的字符串創(chuàng)建所需的對(duì)象,該有多么方便。.net Framwork的反射機(jī)制給我們帶來(lái)了解決問(wèn)題的方法。這里,若只需要?jiǎng)?chuàng)建一般的對(duì)象,我們可以通過(guò)System.Activator來(lái)實(shí)現(xiàn),而較復(fù)雜的我們可以通過(guò)獲取構(gòu)造方法來(lái)實(shí)現(xiàn)。
# 界面/圖表報(bào)表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
看到標(biāo)題,大部分會(huì)說(shuō)“運(yùn)行時(shí)創(chuàng)建對(duì)象”那不是小兒科,就這樣:
Dim newButton As Button = New Button()
newButton.Name = "Button1"
這的確是在運(yùn)行時(shí)創(chuàng)建了一個(gè)按鈕。不過(guò)若需按照用戶要求創(chuàng)建按鈕、復(fù)選框或者單選框怎么辦,好像也好辦:
Dim newControl As Control
Select Case userSelection
Case "按鈕"
newControl = New Button()
Case "復(fù)選框"
newControl = New CheckBox()
....
End Select
如果用戶需要的是Windows.Forms里面的數(shù)十種控件,那么你的Select語(yǔ)句也要寫數(shù)十行嗎?我當(dāng)然不是想要做這種刁難的用戶,但是需求總是多種多樣的,若有一種方法能夠在運(yùn)行時(shí)任意指定對(duì)象的創(chuàng)建類型,甚至是用表示類型的名字的字符串創(chuàng)建所需的對(duì)象,該有多么方便。.net Framwork的反射機(jī)制給我們帶來(lái)了解決問(wèn)題的方法。這里,若只需要?jiǎng)?chuàng)建一般的對(duì)象,我們可以通過(guò)System.Activator來(lái)實(shí)現(xiàn),而較復(fù)雜的我們可以通過(guò)獲取構(gòu)造方法來(lái)實(shí)現(xiàn)。
反射Reflection是.net中重要機(jī)制,很多人已經(jīng)介紹過(guò)反射,我們來(lái)簡(jiǎn)單復(fù)習(xí)一下。通過(guò)反射,可以在運(yùn)行時(shí)獲得.net中每一個(gè)類型(包括類、結(jié)構(gòu)、委派、接口、枚舉)的成員,包括方法、屬性、事件以及構(gòu)造函數(shù)等,還可以獲得每個(gè)成員的名稱、限定符和參數(shù)等,有了反射,就可以對(duì)每一個(gè)類型了如指掌。如果獲得了構(gòu)造函數(shù)的信息,就可以直接創(chuàng)建對(duì)象,即使這個(gè)對(duì)象的類型在編譯的時(shí)候還不知道。
在完成運(yùn)行時(shí)創(chuàng)建控件這一任務(wù)前,我們先看一個(gè)簡(jiǎn)單的例子,建立一個(gè)名為VBAppliction的Windows程序,添加一個(gè)新文件,輸入一個(gè)新類:
Public Class MyClassTest
Private MyField As String
Public Sub New()
MyField = "Hi!"
End Sub
Public Sub Hello()
Console.WriteLine(MyField)
End Sub
End Class
然后加給窗體入一個(gè)新按鈕,輸入以下事件代碼:
''方法一
Dim t As Type = GetType(MyClassTest)
o = System.Activator.CreateInstance(t)
o.Hello()
第一行GetType(MyClassTest)函數(shù)就已經(jīng)獲得了我們創(chuàng)建的類的類型對(duì)象(C#中使用typeof函數(shù))。接下來(lái),我們用了System.Activator類的一個(gè)靜態(tài)方法CreateInstance創(chuàng)建出對(duì)象實(shí)例,并將對(duì)象引用賦給o。Activator是一個(gè)用來(lái)在創(chuàng)建本地或遠(yuǎn)程對(duì)象的工具。運(yùn)行這個(gè)程序,我們可以從Commond Window(命令窗口,一般在調(diào)試狀態(tài)IDE的右下方)看到WriteLine函數(shù)運(yùn)行的結(jié)果,可以看到正確建立的對(duì)象。
如果我們用的類具有比較復(fù)雜的構(gòu)造函數(shù),還可以使用構(gòu)造函數(shù)創(chuàng)建所需的對(duì)象,代碼如下:
''方法二
Dim t As Type = GetType(MyClassTest)
Dim c As System.Reflection.ConstructorInfo
Dim types() As Type
ReDim types(-1)
c = t.GetConstructor(Reflection.BindingFlags.Instance _
Or Reflection.BindingFlags.Public, _
Nothing, Reflection.CallingConventions.HasThis, types, Nothing)
Dim params() As Object
ReDim params(-1)
o.Hello()
這里我們創(chuàng)建一個(gè)System.Reflection.ConstructorInfo的對(duì)象,通過(guò)它可以獲得類構(gòu)造方法的信息。我們用的是Type類的GetConstructor方法來(lái)搜索可用的構(gòu)造方法。
需要解釋一下的是types()數(shù)組,這個(gè)數(shù)組是搜索構(gòu)造方法所用的參數(shù)類型表。我們的類的構(gòu)造方法沒(méi)有參數(shù),所以需要一個(gè)空但不為Nothing(C#中為null)的數(shù)組,ReDim types(-1)就是建立這種數(shù)組的語(yǔ)句,在C#中可寫作:
types = new Type[0];
若構(gòu)造方法是這樣:
Public Sub New(ByVal A As Integer, B As String)
那么相應(yīng)的types數(shù)組就應(yīng)該是
Dim types(1) As Type
types(0) = GetType(Int32)
types(1) = GetType(String)
Reflection.BindingFlags.Instance和Reflection.BindingFlags.Public是一個(gè)位屏蔽,是指定搜索方式的選項(xiàng)。
params()數(shù)組是構(gòu)造方法的參數(shù)內(nèi)容表,同樣因沒(méi)有參數(shù),我們使用ReDim -1的語(yǔ)法。
Invoke方法執(zhí)行了構(gòu)造方法,創(chuàng)建出對(duì)象實(shí)例。
現(xiàn)在我們回到第一種實(shí)現(xiàn)方法,將代碼改一下,將
Dim t As Type = GetType(MyClassTest)
改為
Dim t As Type = Type.GetType("VBApplication.MyClassTest")
運(yùn)行的結(jié)果沒(méi)有改變,這就是說(shuō),我們實(shí)現(xiàn)了從字符串創(chuàng)建對(duì)象!不過(guò)這里GetType方法的使用有限制,具體我們后面再說(shuō)。現(xiàn)在就可以實(shí)現(xiàn)我們的愿望:動(dòng)態(tài)創(chuàng)建控件。通過(guò)上面的知識(shí),我們很容易寫出一個(gè)動(dòng)態(tài)創(chuàng)建窗口控件的子程序:
Private Function CreateNewControls(ByVal targetControls As Control.ControlCollection, ByVal ctlName As String, ByVal ctlType As Type, ByVal ctlSize As Drawing.Size, ByVal ctlLocation As Drawing.Point) As Control
Dim toCreate As Control
toCreate = CType(System.Activator.CreateInstance(ctlType), Control)
toCreate.Name = ctlName
toCreate.Size = ctlSize
toCreate.Location = ctlLocation
targetControls.Add(toCreate)
Return toCreate
End Function
那一句較長(zhǎng)的語(yǔ)句中包含了上一個(gè)例子中的所有內(nèi)容。如果用C#書寫,則可以寫成
toCreate = (Control)System.Activator.CreateInstance(ctlType);
我們將按鈕的事件過(guò)程改成:
Dim c As Control = Me.CreateNewControls1(Me.Controls, "Control1", GetType(CheckBox), New Size(168, 40), New Point(64, 176))
c.Text = "New Creation"
現(xiàn)在,單擊一下按鈕,就可以看到一個(gè)新的CheckBox出現(xiàn)在窗口上,標(biāo)題為New Creation,而且,如果編寫了事件過(guò)程,還可以為新建的控件添加事件響應(yīng)。
看來(lái)一切都達(dá)到目的了?注意這一句GetType(CheckBox)還是使用了類名的字面表示,無(wú)法達(dá)到用字符串創(chuàng)建對(duì)象的功能。如果我們把這一句改成Type.GetType("System.Windows.Forms.CheckBox")行不行?嗯,試驗(yàn)一下,呵呵,出錯(cuò)了。為什么會(huì)這樣?Type.GetType()方法從字符串獲得類型僅限于corlib中的類型或者工程內(nèi)部的類型,如果是來(lái)自于外部的程序集就需要加以程序集的名稱。Windows.Forms程序集是公有的程序集,是位于程序集緩存中的,可以在.net Framwork內(nèi)部實(shí)現(xiàn)side by side執(zhí)行。所以這個(gè)程序集有不同的版本,為了確定使用的版本,我們不僅要提供程序集的名稱,還要提供程序集的版本和強(qiáng)名稱。按照這個(gè)思路,在我使用的.net Framework 1.1上,將這一句寫成Type.GetType("System.Windows.Forms.CheckBox, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")。現(xiàn)在運(yùn)行就沒(méi)有問(wèn)題了。問(wèn)題是我們?nèi)绾稳〉盟肳indows.Forms程序集的版本和強(qiáng)名稱?可以用GetType(CheckBox).AssemblyQualifiedName這樣的語(yǔ)法,一旦得到了這些信息,我們就可以將這些信息用于其它任何控件,因?yàn)樗麄兌紒?lái)自于同一個(gè)版本W(wǎng)indows.Forms程序集。現(xiàn)在可以來(lái)玩一個(gè)好玩的,放一個(gè)文本框到窗口上,比如叫做TextBox1,將按鈕的事件過(guò)程改為:
Try
Dim c As Control = Me.CreateNewControls1(Me.Controls, "Control1", Type.GetType("System.Windows.Forms." & TextBox1.Text & ", System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"), New Size(168, 40), New Point(64, 176))
c.Text = "New Creation"
Catch ex As Exception
MsgBox(ex.Message)
End Try
現(xiàn)在只要在TextBox1種輸入“Button”,按下按鈕,一個(gè)新按鈕產(chǎn)生了!如果輸入的是CheckBox,那么將產(chǎn)生一個(gè)復(fù)選框。現(xiàn)在無(wú)論用戶怎樣刁難,控件都能正確“按需創(chuàng)建”了。反射機(jī)制在.net中還有很多用途,據(jù)說(shuō)Delphi.net中的類引用及虛擬構(gòu)造函數(shù)等功能用于.net Framwork時(shí)就是借助于反射及System.Type類型實(shí)現(xiàn)的,善用這一利器會(huì)給你的程序增色不少。
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請(qǐng)務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請(qǐng)郵件反饋至chenjj@fc6vip.cn
文章轉(zhuǎn)載自:慧都控件網(wǎng)