一引言 對於ncf(net精簡版的英文縮寫)開發人員
應用程序選項保存一般只有兩種途徑選擇
將選項的值寫入注冊表
但如果所有應用程序都將值大量寫入注冊表的做法最終將導致注冊表過大占用系統資源
而影響系統的運行效率
而且這就是很多軟件在硬啟設備之後不得不重新安裝的原因
根據現代程序編寫中
程序盡可能與系統獨立
的思想
這種做法不推薦使用
將選項值以一個初始化文件的方式保存
這樣做可以最大限度避免系統資源占用
提高程序運行獨立性
這種做法個人認為是較為可取的方案
並且這種做法完整版中實現非常簡單
可以直接用Xml序列化類來實現
但在專為智能移動設備定做的net精簡版中
由於不提供XML序列化屬性
使得保存和使用程序選項變得郁悶起來
程序開發人員不得不對每一個程序選項作寫入/讀取文件的編碼
這個枯燥無味的步驟絕對不會是一件有趣的事情
二功能概述 本文中
我將利的反射功能
構建一個自動完成初始化文件的保存/讀寫功能的類
在這個類中
只要程序作者在類內部按程序選項的名稱定義好類的內部成員變量(由於這個步驟仍然需要程序員進行類內的手工編碼
所以稱這個類為半自動初始化類)
這個類就自動將程序選項從初始化文件中保存/讀取的工作
程序員不必再進行繁瑣的讀寫文件部分的編碼
而且
這個類的構建還可以有一個好處
由於應用程序的選項都以成員變量的形式保存在類的內部
程序員可以利用VS提供的自動列出變量成員的功能查詢初始化文件的選項
例如這樣寫 string myAPPname= tobjAPPOption
General
APPName
據我所知
記住大量的程序選項的確切字符也不是什麼好玩的事哦
)
三程序實現先決條件分析 初始化文件內容的需求
我們首先分析觀察一個標准的windows初始化文件win
ini內容
[windows]
load=
run=
NullPort=None
device=HP LaserJet
L PCL
PCL
EMS
\\E
A
B
\HPLaserJ
[Desktop]
Wallpaper=(無)
TileWallpaper=
WallpaperStyle=
該初始化文件的內容用方括號括住的部分我們稱為初始化文件的節
每一節下都組織了一系列與節有相應功能的程序選項
如desktop節下就含有桌面牆紙(Wallpaper)/桌面牆紙鋪設(WallpaperStyle)的設置
在初始化文件中程序的選項大都可以用字符串/數字這些簡單的數據類型進行保存
根據這一需求
考慮到目前中使用xml文件非常方便
而且使用xml格式除可實現常規windows初始化文件的功能外
還可以多出樹形結構組織的優勢
所以本文設計的初始化文件確定采用xml文件格式
並作以下格式的XML文件的元素定義
Net對象以XML元素保存使用的格式定義
Net對象的定義
<Class ObjectName=對象名稱 ObjectType(數據類型)=數據類型 > 數據內容 </數據類型>
數組的定義 目前本類中實現的數組只支持string的一維數組
<Array ObjectName=對象名稱 ObjectType=數據類型 Length=數組大小> 元素定義</Array>
如果數組數組為nothing則格式如下
<Array ObjectName=對象名稱 ObjectType=數據類型 Length=
>nothing</Array>
簡單對象的定義
int
String等
<SimpleObject ObjectName=對象名稱 ObjectType(數據類型)=數據類型 > 數據內容 </數據類型>
當SimpleObject代表數組內的元素時
objectname代表數組的維數
ObjectName
ObjectType
Lenght 屬性的使用舉例如下
例如Redim mai
Test(
) As String
ObjectName取值為mai
Test
ObjectType取值為string[]
Length 值為
中有一種稱之為反射的功能可以枚舉特定類型對象所包含的成員變量的類型及儲存值這個功能經常被一些普通程序員忽略認為用途並不大但在本文中這一功能將成為構建半自動化初始化對象的核心我們正需要這種功能將寫在初始化類中的變量類型和值自動向初始化文件保存或讀取需要使用的反向類型方法及說明如下表
四程序實現核心代碼注釋
我將這個半自動初始化文件類命名為clsAPPOption類內結構及包含過程的功能說明如下
兩個區域#Region 應用程序使用的選項結構定義#Region 應用程序選項的變量聲明中的內容是按初始化選項級組織的類及類的實例每一個類表示程序選項的一個初始化節必須由最終使用者根據實際選項需要自行手工補充
fnGetAppDirectory:取得應用程序的運行目錄
sbInitialDefaultAPPOption設置程序選項的默認初始值(這個過程中的代碼需根據實際需要手工修改)
fnSaveAppOption將類內的程序選項保存到一個指定的文件中 (這個過程中的部分代碼需根據實際需要手工修改)
fnLoadAppOption在指定的文件中讀取應用程序的選項信息並保存到當前類中(這個過程中的部分代碼需根據實際需要手工修改)
fnXMLElementToSimpleObject將一個XMLElement轉為它代表的簡單對象所謂簡單對象就是諸如int\int之類的基本net對象
fnXMLElementToClassObject將一個XMLElement轉換為它代表的類對象
fnXMLElementToArray將一個XMLElement轉為它代表的數組
fnArrayToXML將一個數組放入XML文件中目前只支持一維數組例如dim aString() as string
fnClassObjectToXML將一個類對象轉換為xml元素的表示形式
fnSimpleObjectToXML將一個簡單對象改為XML元素表示
注其中fnXMLElementToXXXX和fnXXXXToXML功能相對應互為反函數
程序的實現是非常簡單的fnClassObjectToXML對指定的類進行反射操作使用類的類型的GetFields方法枚舉類內的成員變量信息然後根據成員變量的類型調用fnSimpleObjectToXML或fnArrayToXML在函數結束的時候將要轉換的類以一個XMLElement對象的形式返回
tobjClassObjectType = ni_objClassObjectGetType 取得類的類型以利於反射調用
…其它代碼
REM 以結構內的所有值進行反射取值 並存入xml對象中
For Each tobjFieldInfo In tobjClassObjectTypeGetFields
If tobjFieldInfoFieldTypeIsArray = False Then 只是一個簡單類型直接取得值
tobjXMLElement = fnSimpleObjectToXML(tobjFieldInfoGetValue(ni_objClassObject) _
ni_objXMLDocument _
tobjFieldInfoName)
tobjXMLClassObjectElementAppendChild(tobjXMLElement)
Else
REM 如果是一個數組類型則進行數組方法的調用以取得值
目前只支持一維數組元素
tobjXMLElement = fnArrayToXML(tobjFieldInfoGetValue(ni_objClassObject) ni_objXMLDocument tobjFieldInfoName tobjFieldInfoFieldTypeFullName)
將數組對象放入結構的xml對象中
tobjXMLClassObjectElementAppendChild(tobjXMLElement)
End If
fnSimpleObjectToXML的實現也很簡單根據前文確立的簡單對象的定義fnSimpleObjectToXML過程所要生成的xml對象的幾個要素可以這樣獲取ObjectName在f nClassObjectToXML作反射後已經獲取並以參數傳遞的方式在調用fnSimpleObjectToXML時提供了 ObjectType數據類型則可以利用ni_objSimpleObjectGetTypeFullName方法取得 ni_objSimpleObject就是在函數調用時傳入的簡單對象的值
在編寫fnArrayToXML過程時出現了一點小問題由於調用方不可能要求數組的元素逐個傳入所以對數組的元素個數以及元素的值無法在函數中以對象反射的方式直接獲取幸運的是在Net反射操作中可以利用Invoke方法來調用原始對象內的函數或屬性過程而數組的共享方法GetLengthGetValue功能適好是取數組元素個數及指定下標的元素值所以問題立刻迎刃而解
利用反射調用數組的getLenght方法取得數組的大小這裡僅支持一維數組但對於初始化文件已足夠用了
tobjXMLAttribute = ni_objXMLDocumentCreateAttribute(ArrayLength)
tobjMethodInfo = tobjArrayTypeGetMethod(GetLength)
ReDim taobjParameter()
taobjParameter() =
tiTempa = tobjMethodInfoInvoke(ni_objArray taobjParameter)
tobjXMLAttributeValue = tiTempa
tobjXMLElementSetAttributeNode(tobjXMLAttribute)
tobjXMLAttribute = Nothing
加入數組的內的元素
For tiLoopA = To tiTempa
利用反射取得數組的GetValue方法取得實際元素的值
ReDim taobjParameterType()
taobjParameterType() = GetType(Integer)
tobjMethodInfo = tobjArrayTypeGetMethod(GetValue taobjParameterType)
ReDim taobjParameter()
taobjParameter() = tiLoopA
tobjTempa = tobjMethodInfoInvoke(ni_objArray taobjParameter)
將數組元素放入對xml對象中
tobjXMLElementA = fnSimpleObjectToXML(tobjTempa ni_objXMLDocument tiLoopA)
tobjXMLElementAppendChild(tobjXMLElementA)
Next tiLoopA
從XML轉為net對象的過程基本都沒有什麼技術難度我只是根據xml中包含的ObjectType信息簡單獲得簡單對象的類型然後直接調用net強制轉換類的功能將XML文件中指定的對象儲存的數值重新恢復為原來的net對象代碼如下
根據XMLelement結構元素中指定的對象類型建立對象
tobjType = TypeGetType(tobjXmlSimpleObjectElementGetAttribute(ObjectType))
tobjReturnSimpleObject = ConvertChangeType(tobjXmlSimpleObjectElementInnerText tobjType Nothing)
對於Xml轉為數組用數組轉為類對象的方法可以參閱本文所附源代碼
初始化文件類實例的調用
類定義完成以後可以在程序的全局范圍定義初始化類的實例在模塊內定義就可以了
Public gobjAppOption As New clsAPPOption
可以在程序啟動的時候讀初始化文件信息到類中我是放在主窗體的load事件中的
讀取程序的選項
gobjAppOptionfnLoadAppOption()
可以在程序的任意地方保存當前半自動初始化類的值到xml文件中我在主窗體的closed事件中加入保存代碼
gobjAppOptionfnSaveAppOption() 保存應用程序的選項
程序的任意地方你都可以調用半自動初始化文件類的實例來讀取/保存程序選項的當前值
可以很好地利用VS提供的自動列出成員的功能列出程序選項
讀取選項的示例代碼
MessageBoxShow(gobjAppOptionmobjAPPGeneralOptionastrShowFileFilter())
保存選項的示例代碼
gobjAppOptionmobjAPPGeneralOptionastrHideFileFilter() = *zip
雖然這個半自動化初始化文件類還是需要手工添加少量代碼(在源代碼明確注釋要手工添加的部分)但還是那句老話如果一切事情電腦都會做的時候離程序員下崗的日子就不遠了
From:http://tw.wingwit.com/Article/program/net/201311/13951.html