很久以前就聽說過反射 了,那時覺得這是個很高深的技術,其實也沒什麼,.Net架構內建的技術,有興趣的朋友可以進
System.Reflection命名空間裡面看看。一直都想把一些技術的心得想下來,一來幫助初學者少走彎路,其實技術都是簡單的,應用才是關鍵,二來我也想復習,三來嘛,希望交些朋友,我的QQ 829098,歡迎同道中人加我。
大家都知道,正常的編碼是這樣的,我們定義好類,通過實例化類來取得對象,調用對象的方法完成我們的任務,可能由一組類來協作一個任務,我們把這些相關類放到一個命名空間裡,生成為一個dll程序集,可以部署的是程序集,而不是類,
我們的系統在運行的時候將把dll(動態鏈接庫)加載到當前進程的一個默認的應用程序域,application.currentdomain.load方法可以取得當前域的所有dll,也可以unload方法將dll從該域卸載掉,通過執行dll的方法來響應用戶的操作,執行完後,就釋放了這個dll.,這是運行時的行為,可以看出
,運行時依賴的是DLL,這對我們開發者而言,DLL是結束而不是開始,因為從編碼到編譯成功,得到PE文件,PE文件之間的關系就固定下來了,DLL就像你煲好的藥,藥材早就變質了,系統也就固定下來不可改了,無法再伸縮它
但是反射它改變了你的想法,你反過來看,你可以從當前進程的應用程序域取得DLL開始(application.currentdomain.load取出該進程的所有的DLL列表),取得DLL裡的類列表或者其他模塊,然後調用類的方法,你看,這個過程是不是運行時才有的,可是你也能在編碼時做到了,你可以把藥材全部找出來
值得注意的是,應用程序的隔離單位從最初的進程為單位,到現在以應用程序域為單位,減少了進程切換帶來的開銷同時又具備隔離的效果.
那麼反射該怎麼理解呢?簡單的說,反射就是可以取得一個dll裡面的所有類或者模塊等等的列表,可以取得每個類或模塊的所有公共和私有成員
可以調用類的方法,或者設置類的變量值,可以根據類名來動態創建對象(當你在類中定義的SUB NEW是PRIVATE的,而你又非要創建它,那麼就反射吧,當然,如果你的SUB NEW帶了參數那就行不通,反正,它是個後門,它破壞了封裝,但是有時候卻非
要它不可, 假如有這麼一個產品類,跟我一起看看,我相信你看了馬上就明白了。
Public Class product
Private mname As String
Property name() As String
Get
Return mname
End Get
Set(ByVal value As String)
mname = value
End Set
End Property
Private mprice As Decimal = 200
Property price() As Decimal
Get
Return mprice
End Get
Set(ByVal value As Decimal)
mprice = value
End Set
End Property
Private mid As Guid = Guid.NewGuid
ReadOnly Property id() As Guid
Get
Return mid
End Get
End Property
Public Sub buy(ByVal number As Integer)
mprice *= number
End Sub
End Class
‘假如這個BUY方法返回買了NUMBER件產品的價格
’那麼利用反射來取得產品類的所有方法
Dim t As Type = Type.GetType("WindowsApplication1.Priduct") ‘通過類型來工作
For Each i As MemberInfo In minfo
If i.Name.Equals("buy") Then
Dim methond As MethodInfo = t.GetMethod("buy")
Dim p() As Object = {5}
MessageBox.Show(c.price.ToString)
methond.Invoke(c, p) ’調用BUY方法
dim c as product =Activator.CreateInstance(t)
MessageBox.Show(c.price.ToString) ‘OK,值被改了,本來是200,現在是1000了,如果傳的參數是負數
,呵呵。那就是負1000了,所以開發者一定要記得在方法裡面做判斷的,這是業務邏輯,不可不寫!
End If
‘取得私有字段也同樣的道理
Dim finfo As FieldInfo() = t.GetFIElds
For Each f As FIEldInfo In finfo
&nb
sp; Dim p() As Object = {2}
If f.Name.Equals("要處理的字段名") Then
MessageBox.Show(c.price.ToString)
f.SetValue(c, p)
MessageBox.Show(c.price.ToString) ’可以看到價格被改了
End If
Next
我們知道有哪些字段了,找出我們關心的,比如price,我們將默認值200改成2的方法是這樣的。
好吧,再來個殺傷力 更厲害的,先在剛才的產品類加個初始化類的方法
private sub new
end sub
假如我們的產品類的sub new是private的,那麼剛才上面的代碼在編寫的時候編譯器 就不讓我們通過了 Dim c As New product (找不到NEW方法嘛),很好,用反射吧OK
Dim t As Type = Type.GetType("WindowsApplication1.Priduct") ’這裡我試了幾次才發現,參數要包括項目的命名空間和類名,也就是完整名稱。之前把命名空間說成項目名,鬧笑話了。呵呵。寫出來還是好,有高人指正。
Dim obj As product= Activator.CreateInstance(t,true) ’傳類型進去即可取得新創建的對象了,注意那個true參數,因為一開始沒傳進去,結果搞了老半天才調試成功,參數2的意思是:nonPublic: 如果公共或非公共默認構造函數可以匹配,則為 true;如果只有公共默認構造函數可以匹配,則為 false。
:
MessageBox.Show(obj.name) ‘OK,成功
大家已經看到了,反射是如此的危險,他可以通過非法路徑來執行你不希望看到的結果。
以上是反射的一般應用,我們試著在實際項目中使用它。下篇文章將作介紹。
有疑問的可以問問。呵呵!
另外在群友的提醒下改了兩個地方的錯誤,1是我用反射的時候是完全靠類型工作的,我之前寫了個創建實例的方法,這可不是晚期綁定,第2個錯誤是我在使用後門方法CreateInstanct時創建實例,此時如果類的構造器是私有的但帶參數,則沒法調用通過,在此感謝該群友 !
2。反射的項目實戰,將枚舉轉換成列表的辦法
3。按位運算的項目實踐,接上文的反射項目實踐