程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> Visual Basic語言 >> VB.NET >> VB.NET為智能設備編寫半自動初始化類

VB.NET為智能設備編寫半自動初始化類

編輯:VB.NET

一、引言

對於ncf(net精簡版的英文縮寫)開發人員,應用程序選項保存一般只有兩種途徑選擇:

1、將選項的值寫入注冊表,但如果所有應用程序都將值大量寫入注冊表的做法最終將導致注冊表過大占用系統資源,而影響系統的運行效率;而且這就是很多軟件在硬啟設備之後不得不重新安裝的原因。根據現代程序編寫中"程序盡可能與系統獨立"的思想,這種做法不推薦使用。

2、將選項值以一個初始化文件的方式保存,這樣做可以最大限度避免系統資源占用,提高程序運行獨立性,這種做法個人認為是較為可取的方案。並且這種做法在.net完整版中實現非常簡單,可以直接用Xml序列化類來實現。但在專為智能移動設備定做的net精簡版中,由於不提供XML序列化屬性,使得保存和使用程序選項變得郁悶起來。程序開發人員不得不對每一個程序選項作寫入/讀取文件的編碼,這個枯燥無味的步驟絕對不會是一件有趣的事情。

二、功能概述

本文中,我將利用.net的反射功能,構建一個自動完成初始化文件的保存/讀寫功能的類。在這個類中,只要程序作者在類內部按程序選項的名稱定義好類的內部成員變量(由於這個步驟仍然需要程序員進行類內的手工編碼,所以稱這個類為半自動初始化類),這個類就自動將程序選項從初始化文件中保存/讀取的工作,程序員不必再進行繁瑣的讀寫文件部分的編碼。而且,這個類的構建還可以有一個好處:由於應用程序的選項都以成員變量的形式保存在類的內部,程序員可以利用VS提供的自動列出變量成員的功能查詢初始化文件的選項。例如這樣寫 string myAPPname= tobjAPPOption.General.APPName。據我所知,記住大量的程序選項的確切字符也不是什麼好玩的事哦8-)

三、程序實現先決條件分析

1、初始化文件內容的需求

我們首先分析觀察一個標准的windows初始化文件win.ini內容:

[windows]
load=
run=
NullPort=None
device=HP LaserJet 6L PCL,PCL5EMS3,\E5A18B631240425HPLaserJ 
[Desktop]
Wallpaper=(無)
TileWallpaper=1
WallpaperStyle=0

該初始化文件的內容用方括號括住的部分我們稱為初始化文件的節,每一節下都組織了一系列與節有相應功能的程序選項。如desktop節下就含有桌面牆紙(Wallpaper)/桌面牆紙鋪設(WallpaperStyle)的設置。在初始化文件中程序的選項大都可以用字符串/數字這些簡單的數據類型進行保存。

根據這一需求,考慮到目前在.net中使用xml文件非常方便,而且使用xml格式除可實現常規windows初始化文件的功能外,還可以多出樹形結構組織的優勢,所以本文設計的初始化文件確定采用xml文件格式。並作以下格式的XML文件的元素定義:

'Net對象以XML元素保存使用的格式定義
'Net對象的定義
'<Class ObjectName=對象名稱 ObjectType(數據類型)=數據類型 > 數據內容 </數據類型>
'數組的定義 目前本類中實現的數組只支持string的一維數組
'<Array ObjectName=對象名稱 ObjectType=數據類型 Length=數組大小> 元素定義</Array>
'如果數組數組為nothing則格式如下
'<Array ObjectName=對象名稱 ObjectType=數據類型 Length=0>nothing</Array>
'簡單對象的定義'int32、String等
'<SimpleObject ObjectName=對象名稱 ObjectType(數據類型)=數據類型 > 數據內容 </數據類型>
'當SimpleObject代表數組內的元素時,objectname代表數組的維數
'ObjectName 、ObjectType、 Lenght 屬性的使用舉例如下
'例如Redim mai32Test(7) As String
'ObjectName取值為mai32Test,ObjectType取值為string[],Length 值為8

2、在.net中有一種稱之為反射的功能,可以枚舉特定類型對象所包含的成員變量的類型及儲存值,這個功能經常被一些普通程序員忽略,認為用途並不大。但在本文中,這一功能將成為構建半自動化初始化對象的核心,我們正需要這種功能將寫在初始化類中的變量類型和值自動向初始化文件保存或讀取。

四、程序實現核心代碼注釋

1、我將這個半自動初始化文件類命名為clsAPPOption,類內結構及包含過程的功能說明如下:

兩個區域#Region "應用程序使用的選項結構定義"、#Region "應用程序選項的變量聲明"中的內容是按初始化選項級組織的類及類的實例,每一個類表示程序選項的一個初始化節,必須由最終使用者根據實際選項需要自行手工補充。

fnGetAppDirectory:取得應用程序的運行目錄

sbInitialDefaultAPPOption:設置程序選項的默認初始值(這個過程中的代碼需根據實際需要手工修改)

fnSaveAppOption:將類內的程序選項保存到一個指定的文件中. (這個過程中的部分代碼需根據實際需要手工修改)

fnLoadAppOption:在指定的文件中讀取應用程序的選項信息並保存到當前類中(這個過程中的部分代碼需根據實際需要手工修改)

fnXMLElementToSimpleObject:將一個XMLElement轉為它代表的簡單對象,所謂簡單對象就是諸如int32int16之類的基本net對象

fnXMLElementToClassObject:將一個XMLElement轉換為它代表的類對象

fnXMLElementToArray:將一個XMLElement轉為它代表的數組

fnArrayToXML:將一個數組放入XML文件中,目前只支持一維數組:例如dim aString(10) as string

fnClassObjectToXML:將一個類對象轉換為xml元素的表示形式

fnSimpleObjectToXML:將一個簡單對象改為XML元素表示

注:其中fnXMLElementToXXXX和fnXXXXToXML功能相對應,互為反函數。

2、程序的實現是非常簡單的,fnClassObjectToXML對指定的類進行反射操作,

使用類的類型的GetFields方法枚舉類內的成員變量信息,然後根據成員變量的類型調用fnSimpleObjectToXML或fnArrayToXML,在函數結束的時候,將要轉換的類以一個XMLElement對象的形式返回。

tobjClassObjectType = ni_objClassObject.GetType '取得類的類型,以利於反射調用

….其它代碼

REM 以結構內的所有值進行反射取值, 並存入xml對象中

For Each tobjFieldInfo In tobjClassObjectType.GetFields
If tobjFieldInfo.FieldType.IsArray = False Then '只是一個簡單類型,直接取得值
tobjXMLElement = fnSimpleObjectToXML(tobjFieldInfo.GetValue(ni_objClassObject), _
ni_objXMLDocument, _
tobjFieldInfo.Name)
tobjXMLClassObjectElement.AppendChild(tobjXMLElement)
Else
REM 如果是一個數組類型,則進行數組方法的調用以取得值,
'目前只支持一維數組元素
tobjXMLElement = fnArrayToXML(tobjFieldInfo.GetValue(ni_objClassObject),

ni_objXMLDocument, tobjFieldInfo.Name, tobjFieldInfo.FieldType.FullName)
'將數組對象放入結構的xml對象中
tobjXMLClassObjectElement.AppendChild(tobjXMLElement)
End If

fnSimpleObjectToXML的實現也很簡單,根據前文確立的簡單對象的定義,fnSimpleObjectToXML過程所要生成的xml對象的幾個要素可以這樣獲取:ObjectName在f nClassObjectToXML作反射後已經獲取,並以參數傳遞的方式在調用fnSimpleObjectToXML時提供了。 ObjectType數據類型則可以利用ni_objSimpleObject.GetType.FullName方法取得, ni_objSimpleObject就是在函數調用時傳入的簡單對象的值。

從XML轉為net對象的過程基本都沒有什麼技術難度。我只是根據xml中包含的ObjectType信息簡單獲得簡單對象的類型,然後直接調用net強制轉換類的功能將XML文件中指定的對象儲存的數值重新恢復為原來的net對象。代碼如下:

'根據XMLelement結構元素中指定的對象類型,建立對象
tobjType = Type.GetType(tobjXmlSimpleObjectElement.GetAttribute("ObjectType"))
tobjReturnSimpleObject =

Convert.ChangeType(tobjXmlSimpleObjectElement.InnerText, tobjType, Nothing)

對於Xml轉為數組用數組、轉為類對象的方法可以參閱本文所附源代碼。

3、初始化文件類實例的調用:

類定義完成以後,可以在程序的全局范圍定義初始化類的實例。在模塊內定義就可以了:

Public gobjAppOption As New clsAPPOption

可以在程序啟動的時候讀初始化文件信息到類中,我是放在主窗體的load事件中的。

'讀取程序的選項
gobjAppOption.fnLoadAppOption()

可以在程序的任意地方保存當前半自動初始化類的值到xml文件中,

我在主窗體的closed事件中加入保存代碼:

gobjAppOption.fnSaveAppOption() '保存應用程序的選項

程序的任意地方你都可以調用半自動初始化文件類的實例來讀取/保存程序選項的當前值:

'可以很好地利用VS提供的自動列出成員的功能列出程序選項
'讀取選項的示例代碼
MessageBox.Show(gobjAppOption.mobjAPPGeneralOption.astrShowFileFilter(0))
'保存選項的示例代碼
'gobjAppOption.mobjAPPGeneralOption.astrHideFileFilter(0) = "*.zip"

雖然這個半自動化初始化文件類還是需要手工添加少量代碼(在源代碼明確注釋要手工添加的部分),但還是那句老話,如果一切事情電腦都會做的時候,離程序員下崗的日子就不遠了。

在編寫fnArrayToXML過程時出現了一點小問題,由於調用方不可能要求數組的元素逐個傳入,所以對數組的元素個數以及元素的值無法在函數中以對象反射的方式直接獲取。幸運的是,在Net反射操作中,可以利用Invoke方法來調用原始對象內的函數或屬性過程,而數組的共享方法GetLength、GetValue功能適好是取數組元素個數及指定下標的元素值,所以問題立刻迎刃而解。

'利用反射調用數組的getLenght方法取得數組的大小,這裡僅支持一維數組,但對於初始化文件已足夠用了
tobjXMLAttribute = ni_objXMLDocument.CreateAttribute("ArrayLength")
tobjMethodInfo = tobjArrayType.GetMethod("GetLength")
ReDim taobjParameter(0)
taobjParameter(0) = 0
ti32Tempa = tobjMethodInfo.Invoke(ni_objArray, taobjParameter)
tobjXMLAttribute.Value = ti32Tempa
tobjXMLElement.SetAttributeNode(tobjXMLAttribute)
tobjXMLAttribute = Nothing
'加入數組的內的元素
For ti32LoopA = 0 To ti32Tempa - 1
'利用反射取得數組的GetValue方法取得實際元素的值 
ReDim taobjParameterType(0)
taobjParameterType(0) = GetType(Integer)
tobjMethodInfo = tobjArrayType.GetMethod("GetValue", taobjParameterType)
ReDim taobjParameter(0)
taobjParameter(0) = ti32LoopA
tobjTempa = tobjMethodInfo.Invoke(ni_objArray, taobjParameter)
' 將數組元素放入對xml對象中
tobjXMLElementA = fnSimpleObjectToXML(tobjTempa, ni_objXMLDocument, ti32LoopA)
tobjXMLElement.AppendChild(tobjXMLElementA)
Next ti32LoopA

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved