top
Loading...
VB中運用反射原理優化程序代碼
在這個項目里我負責的部分是讀取某子系統從數據庫導出來的兩個XML(不妨假設為A.XML和B.XML)文件并根據文件內容完成本部分的業務工作流程。文件是以共享方式放在服務器上,我只需要獲得一個Session訪問即可,因為要求是實時讀寫文件,所以否定了下載到本地進行讀寫的方法,而為了保證程序生命力和數據的完整性,我決定將文件信息一次性讀入程序存儲空間,并在業務流程中設定當完成某個特定的步驟后回寫一遍AB兩文件,其中A文件節點可能有增刪B文件只是更新某個標志。

一開始設計具體類的時候很容易想到構造和文件結構對應的類,使用龐大的DOM對象?哦,我可不需要那么多累贅。現在我把對應AB兩文件的類分別寫了個大概出來,很簡單如下:

Class clsA/B
Property Name1 as string
...
End Property
Property Name2 as string
...
End Property
......
......
......
End Class

A,B各需要要一個集合類管理,分別命名為clscolA,clscolB,大概如下:

Public Class clscolA/B
Inherits System.Collections.CollectionBase
Public Function GenerateAson() As clsA/clsB
'New并返回一個 clsA or clsB
'初始化屬性的工作可以在這里進行
End Function
Public Sub AddSon(ByVal objSon As clsA/clsB)
'增加一條新紀錄
InnerList.Add(objSon)
End Sub
Public Sub Sort()
'根據某設定的屬性對集合進行排序
InnerList.Sort(New clsSortByName)
End Sub
'默認Item屬性以及更多Method從略
End Class

好了,現在程序數據的基本框架搭好了,這無疑是十分中庸地解決辦法,當然也是十分有效的,本文的主題并不是特別愿意刪減這些成熟的代碼(當然也僅僅是暫且不動而已)。軀殼已有,剩下的工作就是從文件讀取并填充數據,如果你還沒有接觸過反射或者僅僅限于書本上那點例子,這對你來說可能是一個簡單而又枯燥的過程,你于是乎也條件反射似地寫起來

New一個clscolA/B(就叫colA/B吧)然后遍歷文件或取一個包含所有記錄(目標節點)的NodeList,然后作如下狀:

With NodeList
for i as integer=0 to .Count-1
Dim objson as clsA/B=colA/B.GenerateAson
objson.Name1=.item(i).childnodes(x1).innertext
objson.Name2=.item(i).childnodes(x2).innertext
......
......
......
colA/B.Addson(objson)
next i
End With

這段代碼雖然他夠用,又看似天衣無縫,但總覺得不對頭,當屬性達到一定數量,你有沒有發現你將會使用了太多的同樣的賦值句?小學語文就告訴過我們適當使用排比句可以為文章造勢,但是如果你一口氣排比了20條,那就是濫用了,筆者這里A文件每一條記錄有三十多個Field,B文件也有十多個,如果這樣用下來景象肯定巍巍壯觀,先估計一下代碼量,A文件每條記錄按30個Field,B按15個算,賦值過程便是45行,還不包括格式化處理和排錯處理,如果考慮程序擴展性,以后要讀更多的文件則必然會伴隨更多類似的過程出現,寫程序和做人一樣,要低調,一定要低調啊,有激情的程序員自然不會如此糟蹋自己的代碼,是否能用一個函數或過程解決上述問題呢?新方案應用而生,采用反射(Imports/using System.Reflection),一個通用過程解決所有問題。示例函數如下:

Public Shared Function FillFromXml(ByVal NodeName As String, ByVal strPath As String, ByVal objFather As Object) As Boolean
Try
With xmlGetList(NodeName, strPath)
For i As Integer = 0 To .Count - 1
Dim st As Object = objFather.GenerateAson
Dim ty As Type = st.GetType
For Each pp As PropertyInfo In ty.GetProperties
With DirectCast(.Item(i), XmlElement)
If .SelectSingleNode(pp.Name.ToUpper) IsNot Nothing Then
pp.SetValue(st, CType(.SelectSingleNode(pp.Name.ToUpper).InnerText.Trim, String), Nothing)
End If
End With
Next
objFather.AddSon(st)
Next
End With
Return True
Catch ex As Exception
Return False
End Try
End Function

使用這個函數,只需要保證集合類clscolA/B有GenerateAson和Addson兩個方法以及clsA/B兩子類的屬性名稱與文件中Field保持一致即可。你只需要傳遞相應A或者B文件的目標節點名,文件路徑,以及對應的集合類即可,此時再看一下賦值過程的代碼減少了多少,恩,只有8行,這對于筆者則意味著省去了45-8=37行代碼,而且丟棄老套的排比句。

第一階段戰斗算是小試牛刀了一把,如果只算賦值過程代碼減少百分數為37/45,接近83%。

你也可能抱怨我上面的百分數計算太不科學,要算也應該拿全部來算,那就不妙了,好吧,看來也只能拿十分“老的““成熟“的來開刀了,下面便是削減代碼二期工程,我們的目標是讓成熟變干練,太過成熟的確不合某些同志的胃口。對應于AB兩文件的類clsA/B,分別至少有30和15個屬性,還好,也不過就一二百行代碼就搞定,更簡單點就用自己寫的代碼生成器,一次性生成所有屬性,并不會很麻煩。不過還是有更好(準確使更精簡)的解決辦法,用一個通用類,十分之一的代碼(實際應用中會更少)就可以做到。

這其實不過是一個繼承了字典的子類,如下:

Public Class clsCommon
Inherits System.Collections.DictionaryBase
Public Sub AddField(ByVal FieldName As String, ByVal value As Object)
Dictionary.Add(FieldName, value)
End Sub

Default Public Property Item(ByVal key As String) As Object
Get
Return Dictionary.Item(key)
End Get
Set(ByVal value As Object)
Dictionary.Item(key) = value
End Set
End Property
End Class

這個通用類提供兩個基本的方法,意義顯而易見,而其對應的集合類基本還是原來那個樣子:

Public Class clscolCommon
Inherits System.Collections.CollectionBase
Public Function GenerateAson() As clsCommon
End Function

Public Sub AddSon(ByVal objSon As clsCommon)
End Sub
Public Sub Sort()
End Sub
'默認Item屬性以及更多Method從略
End Class

不過這時候賦值過程也需要更改一下:

With xmlGetList(NodeName, strPath)
For i As Integer = 0 To .Count - 1
Dim st As Object = objFather.GenerateAson
With DirectCast(.Item(i), XmlElement)
For Each ch As XmlNode In .ChildNodes
St.AddField(ch.Name,ch.InnerText)
Next
End With
objFather.AddSon(st)
Next
End With

本文至此,削減代碼工程算是小有成就,如果真要計算削減了多少,我想還是能夠對得起這個標題的,而關于如何回寫文件,必然也仍然是反射,肯定有更好的辦法,在這里就不贅述了。

作者:http://www.zhujiangroad.com
來源:http://www.zhujiangroad.com
北斗有巢氏 有巢氏北斗