集合類:VBA集合對象的安全包裝

你遲早都要管理一組由VBA類模塊創建的自定義對象,VBACollection對象是實現這一目的的理想工具。我們在該雜志的PRemiere期刊中曾經介紹過Collections,並且闡述了如何使用Collection對象來存儲其他對象。雖然該項技術十分有用,但它確實還存在一些局限。在本文中,我們討論了這些局限,並向你展示如何通過使用(你猜是什麽)類模塊來克服這些局限。

Collections中遇到的麻煩

Collections對象中到底有什麽問題呢?它似乎存儲對象存儲得非常好。事實上,它工作起來的確是太好了。Collections對象得最大問題是它可以存儲到任何數據類型得引用,例如Integer,String,Long,Variant,等(見圖1)。

當然,如果你能保證每個對象都具有相同得類型,並且具有相同得屬性何方法的話,那麽在Collection中處理對象就變得異常簡單。例如,作爲本月範例ExcelVBA項目的組成部分,我們創建一個自定義的File類來代表一個磁盤文件。這個File類有幾個屬性,其中包括Path,Size,和ShortName。如果你創建了一個File對象的Collection,那麽你將希望這個Collection中的每個對象都具有這些屬性。你可以毫無異議地使用與下面類似的代碼:

'PrintthesizeofthefirstfileintheCollection.

Debug.PrintcolFiles.Item(1).Size

但是,如果colFilesCollection中的第一個對象不是File,將會出現什麽情況呢?如果它是一個Form或Control對象,又會怎樣呢?如果它根本就不是一個對象呢?當然,當它試圖執行該代碼的時候,VBA將生成運行時間錯誤。

集合類:VBA集合對象的安全包裝

圖1(左)VBACollection對象可以容納任何類型的對象

集合類:VBA集合對象的安全包裝

圖2(右)創建一個Collection類來防止不想要的對象進入集合

輸入Collection類

Collection類可以充當Collection對象的過濾器,限制你可以在裏面存儲的對象類型(如圖2所示)。通過與你的應用程序中的Collection類(二不是Collection對象本身)的互相作用,你可以防止不想要的對象的進入。創建和使用Collection類允許你擴展Collection對象的屬性和方法(後面我們將舉例說明)。

爲了說明Collection類以及如何創建一個Collection類,我們將使用帶有通過掃描磁盤目錄創建的文件集合的Excel97項目。圖3顯示了一個表單,它用你選擇了路徑之後存儲在自定義Collection類中的文件信息使得列表框通俗化。

這個表單使用一個叫做Files的Collection類來通俗化列表框。在創建Collection的時候,以向你的VBA項目添加一個新的類模塊作爲開始,然後在這個新模塊的聲明段聲明一個PrivateCollection對象。下面是來自Files類模塊的聲明:

'Collectionoffiles.

PrivatepcolFilesAsNewCollection

爲了將Collection對象與外界"隔絕",並阻止程序的其他部分用無用的東西填充它,必須將Collection對象聲明爲Private。

複制所需要的方法

當然,一旦你已經將Collection對象聲明爲Private,那麽對于任何過程都沒有辦法向其中添加項目或從中刪除項目了。因而,下一步就是複制Collection對象的標准方法了。盡管聽起來象是做了大量額外的工作,實際上仍然在做我們前面所提及的"過濾"工作。

請記住,內建的Collection對象具有Add方法,該方法接受對象引用和獨特的、包括文字與數字的標識符。如果你的應用程序正在直接使用Collection對象,那麽它將極有可能創建對象的一個新的實例,並將其添加到Collection本身。

'Createanewinstanceofanobject.

DimobjFileAsNewFile

objFile.Path="C:AUTOEXEC.BAT"

'AddtoaCollectionobject.

colFiles.AddobjFile,objFile.ShortName

應用Collection類,應用程序調用該類的Add方法,傳遞任何必需的信息。請將先前的代碼與Files類的Add方法做一比較:

WithaCollectionclass,theapplicationcallstheAddmethodoftheclass,passinganyrequiredinformation.ContrastthepreviouscodewiththeAddmethodoftheFilesclass:

PublicFunctionAdd(PathAsString)AsFile

DimobjFileAsFile

'CreatethenewFileobject.

SetobjFile=NewFile

objFile.Path=Path

'AddittothePrivatecollection.

pcolFiles.AddobjFile,objFile.ShortName

'Returnapointertothenewobject.

SetAdd=objFile

EndFunction

在本例中,到Collection的對象創建和添加發生在Add方法內部;而類則保留了完整的控制。任何必需的信息(例如文件的路徑)是作爲參數向方法提供的。由應用程序調用將文件添加到Collection的代碼然後可以簡化爲:

'Addafiletothecollection.

colFiles.Add"C:AUTOEXEC.BAT"

InadditiontotheAddmethod,theCollectionclassshouldalsoimplementtheItemandRemovemethods,aswellasaCountproperty:

PublicFunctionItem(KeyAsVariant)AsFile

'Returnaniteminthecollection.

SetItem=pcolFiles.Item(Key)

EndFunction

PublicSubRemove(KeyAsVariant)

'Removeanitemfromthecollection.

pcolFiles.RemoveKey

EndSub

PropertyGetCount()AsLong

'Returnthenumberofitems.

Count=pcolFiles.Count

EndProperty

請注意,在這三種方法中,我們省略了錯誤處理--有些事情你是從來都不應該做的!至少應該包括一個錯誤處理器,通過使用Err對象的Raise方法來將錯誤傳遞、給調用過程。

圖3這個表單通過顯示文件信息來說明Collection類

'Privatevariabletostorepath.

PrivatepstrPathAsString

PropertyGetPath()AsString

'Returnstoredpathvalue.

Path=pstrPath

EndProperty

PropertyLetPath(strPathAsString)

DimstrFileAsString

'Clearthecollection.

SetpcolFiles=NewCollection

'Makesurethere'sabackslash.

IfRight(strPath,1)<>""Then

strPath=strPath&""

EndIf

'Getthefirstfile.

strFile=Dir(strPath&"*.*",_

vbReadOnlyOrvbHiddenOrvbArchiveOrvbSystem)

DoUntilLen(strFile)=0

'Addittothecollection.

CallAdd(strPath&strFile)

'Getthenextfile.

strFile=Dir()

Loop

'Savethepath.

pstrPath=strPath

EndProperty

圖4向Collection類添加Path屬性。將該屬性和類設置爲掃描目錄並將所找到的每個文件添加到私有Collection對象。

擴展Collection類

現在,你可以通過聲明Files類的一個實例來使用它了,並爲曾經由Dir函數找到的每個文件反複調用該類的Add方法。但這不是我們的例子要完成的工作。爲什麽不是呢?使用Collection類的一個優點是你可以通過添加更多的屬性和方法來擴展它的功能;不僅僅限于Add,Remove,Item,和Count。

在我們的Files類的情形中,它難道不對在類本身,而不是使用該類的每個應用程序裏面,放置掃描目錄的代碼做更多的檢測嗎?這是面向對象設計的一個指導原則:將代碼放在最靠近需要它的地方。

爲了闡述這個概念,我們向Collection類添加了一個Path屬性。當你設置這個屬性的時候,這個類將對目錄進行掃描,並向Collection對象添加它所找到的每個文件(見圖4)。

當一個過程改變該類的Path屬性的時候,將觸發PropertyLet過程。在我們的例子中,它發生在你從浏覽器對話框選擇了一個路徑之後。這裏是完成用文件列表填充Collection任務的簡單代碼。

'Reinitializethecollection.

SetmobjFiles=NewFiles

'Setthepathproperty.

mobjFiles.Path=strPath

一旦設置了Path屬性,Files類就將通俗化它自己的Collection,並且使它可以提供給應用程序。這已經是另一個例子了,在這個例子裏面,過程的"guts"存在于類自己內部(你可以證明類已不再需要它的Add和Remove方法了。在有些應用程序中,可能確實是這樣,但爲了達到說明的目的,我們已經選擇了留下它們作爲該類的一部分)。

一些不利之處

使用VBACollection類的生活並不總是美酒和玫瑰。當你使用Collection類代替Collection對象時,必須放棄兩樣東西。第一樣是Collection對象的默認方法,Item。默認的方法允許你從你的代碼中省略單詞"Item"。例如,如下兩條語句是一樣的,都是假定colFiles引用一個Collection對象。

Debug.PrintcolFiles.Item(1).Size

Debug.PrintcolFiles(1).Size

除非你正在使用的是VisualBasic5.0,否則沒有辦法爲一個類指定默認的方法。因而,你必須總是顯式調用Item方法。

Collection類的第二個主要的不足之處是不能創建列舉函數。列舉類就是可以使ForEach循環工作的類。如果你想重複Collection中的每一個項目,那麽就必須用老式的方法來完成,也就是使用Count屬性和ForNext循環。例如,下面的代碼可以通俗化列表框:

'Fillthelistboxwithinfo.

lstFiles.Clear

ForlngCount=1TomobjFiles.Count

WithmobjFiles.Item(lngCount)

lstFiles.AddItem.ShortName&_

Space(12-Len(.ShortName))&_

vbTab&.AttributeString&_

vbTab&.Size

EndWith

Next

請注意該過程是如何使用計數器變量lngCount來完成從1到Collection中項目數的循環的。With語句使用了Item方法來引用Collection中的每個對象。

請注意,VisualBasic5.0用戶可以通過創建列舉函數來克服這一局限。在VisualBasicBookOnline中搜索關鍵字"enumeration"可以得到更爲詳細的信息。-

C#3.0 中對象初始化器(Object Initializers)和集合初始化器(Collection Initializers)
C# 3.0 中對象初始化器(Object Initializers) 和 集合初始化器(Collection Initializers) ,就是簡化我們的代碼,讓本來幾行才能寫完的代碼一行寫完。這樣在LINQ的使用中,我們才不會把一個LINQ表達式寫的巨複雜無比...查看完整版>>C#3.0 中對象初始化器(Object Initializers)和集合初始化器(Collection Initializers)
 
C#3.0 中對象初始化器(Object Initializers)和集合初始化器(Collection Initializers)
C# 3.0 中對象初始化器(Object Initializers) 和 集合初始化器(Collection Initializers) ,就是簡化我們的代碼,讓本來幾行才能寫完的代碼一行寫完。這樣在LINQ的使用中,我們才不會把一個LINQ表達式寫的巨複雜無比...查看完整版>>C#3.0 中對象初始化器(Object Initializers)和集合初始化器(Collection Initializers)
 
Win2003下編輯組策略對象上的安全設置
  1.執行這些步驟中的某個步驟: 如果 執行 您正在使用加入域的工作站或服務器,可以修改組策略對象安全設置 ?單擊“開始”,指向“運行”,鍵入“m...查看完整版>>Win2003下編輯組策略對象上的安全設置
 
我對象12月21號來的月經,一月十四號做愛,周期是三十天,會懷孕嗎?一般後安全期是幾天?
據你所說的情況按月經周期是30天推算,得出你女朋友的安全期和排卵期日程如下:12月21號--31號,是前安全期。1月1號--8號,是排卵期。1月9號--19號,是後安全期。依據上述日程看來,1月14號已經在後安全期之內,那天...查看完整版>>我對象12月21號來的月經,一月十四號做愛,周期是三十天,會懷孕嗎?一般後安全期是幾天?
 
對象序列化的安全性
在進行對象序列化時,要想保證安全性,可以:1。把敏感數據字段設爲transient2。不要使用保存和還原對象的默認機制。...查看完整版>>對象序列化的安全性
 
機械行業標准:包裝機械安全要求
1 主題內容與適用範圍  本標准規定了包裝機械的安全要求,包括防護、操作和維護要求等。  本標准適用于直接進行包裝的機器與設備。2 引用標准 GB2893 安全色 GB2894 安全標志 GB3766 液壓系統通用技術條件...查看完整版>>機械行業標准:包裝機械安全要求
 
藥品安全由包裝開始
藥品安全由包裝開始 無論選用何種技術,包裝設計都要求對最壞的情況進行考量。 在包裝階段執行産品安全,有點像在一個有長長9頁菜單的餐廳點菜,總是有如此多的選擇,以至于你剛剛點好菜,...查看完整版>>藥品安全由包裝開始
 
論食品包裝與食品安全
論食品包裝與食品安全 摘要:食品包裝與食品安全有密切的關系,食品包裝必須保證被包裝食品的衛生安全,才能成爲放心食品。國家對食品包裝有哪些具體規定?食品包裝、食品生産企業和消費者應該注意哪些主要方面的...查看完整版>>論食品包裝與食品安全
 
食品包裝安全包裝性性能簡析
食品包裝安全包裝性性能簡析 食品軟包裝材料主要有聚乙烯、聚丙烯、聚酯、聚酰胺等高分子材料。這些包裝材料因本身分子結構和成型工藝及所加助劑不同而表現出較大差異。因此,對于食品廠家來說選擇一種適合自己産...查看完整版>>食品包裝安全包裝性性能簡析
 
 
回到王朝網路移動版首頁