荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: Jobs (温少), 信区: Visual
标  题: 利用VB6 中Dictionary对象的强大功能
发信站: BBS 荔园晨风站 (Mon Mar  6 10:55:51 2000), 转信



利用Visual Basic 6.0 中Dictionary对象的强大功能

Dictionary对象将替换Collection对象,并提供附加的语言从而使增加和删除记
录的速度比以前提高三倍

虽然Visual Basic 6.0只有很少的新特点,但是具有某些功能强大的新的对象模
型,其中之一就是Dictionary对象。

Dictionary对象是无处不在的Visual Basic Collection对象的新版本。它的介绍
存在于VBScript 2.0,并通过Visual Basic 6.0对Scripting Runtime Library的
支持涉入Visual Basic的全部内容。刚开始,Dictionary对象仅仅包含在
VBScript中,并作为Perl相关内容的等价体对Web组请求进行答复。

与Collection对象相似,你能够通过Dictionary存储任何类型的数据或字典对象
,这些数据和对象通常被看作字典的组成部分,每一部分都被赋予字符串型键值
。虽然我不认为Microsoft意图使你完全摆脱收集和替换上述数据和对象的烦恼,
但是实际上,在先前的Visual Basic 6.0文档中,对Dcitionary对象确实很少提
及,因此我认为这是Visual Basic 6.0的一个最新的重要特点。


Dictionary对象与Collection对象的比较

从Visual Basic 4.0开始,Collection对象就作为主要的数据类型替代了用户自
己定义的类型,由此以后,大多数Visual Basic程序都包含Collection对象。如
果你从Visual Basic 4.0开始已经非常习惯于使用Collection对象,那么你又为
什么需要作出改变呢?这主要有几个因素:


Dictionary对象比Collection 对象更快,这种速度优势主要体现在增加数据成员
、在字典中进行迭代搜索和删除数据成员上。

Dictionary对象包括那些你经常不得不自己编制的封装函数,例如Exists函数和
RemoveAll函数。

Dictionary对象让你能够创建Key值数组和Item值数组,从而加快在字典中进行迭
代搜索的速度。


Dictionary对象让你能够覆盖已经存在的Key值和已经存在的数据成员。
Dictionary对象还确实存在着下述缺点,但它们本身并不值一提:

与Collection对象不同,Dictionary对象不是VBA语言DLL的一部分,这意味着你
需要借助SCRRUN.DLL,并将之连接到相应的应用程序。

Dictionary对象实现For…Each…Next循环的方法也很奇怪,它不是返回Item值,
而是返回Key值。

Dictionary对象还有一恼人之处,就是如果你想从字典中删除一个没有搜索到的
成员,你就必须添加数据到这个空的条目或不存在的键。

访问Dictionary对象
正如我先前所说,Dictionary对象不是VBA或Visual Basic实时语言的具体存在的
部分,它是存在于Microsoft Scripting Runtime Library(SCRRUN.DLL)中的一
个对象。为了在应用程序中使用Dictionary对象,就必须利用Reference对话框增
加一个项目级的引用到Scripting Runtime Library。


增加完引用之后,创建Dictionary对象的实例,如下:
Dim oDict As Dictionary
Set oDict = New Dictionary
' Do some work.
Set oDict = Nothing

为了增加一个成员到Dictionary对象,利用Add方法,其中包括两个参数:需要增
加的数据和与数据相关联的字符串型Key值,语法如下:
dictionary.Add Key, Data

在Dictionary对象中没有指明新的数据成员存放位置的参数,它将由字典自己挑
出。你还需要注意Add方法的参数正好与Collection对象的Add方法相反,在
Collection对象 中:

collection.Add Data, [Key], [before], [after]


与Collection对象类似,Dictionary对象的成员能够是任何数据类型、对象或其
他字典,从而使你能够按照自己的意愿任意嵌套Dictionary对象。

访问Dictionary对象的成员
Dictionary对象的Item方法是访问包含在字典中数据的推荐方法,其好处是速度
快,非常快。我所做的测试表明,访问Dictionary对象数据成员的速度要比访问
Collection对象数据成员的速度快三倍。如果你打开对象浏览器,选择
Dictionary对象,并观察隐藏的成员,你就会看到名为HashVal的属性,这表明
Dictionary对象存在无用信息列表和一些奇怪的排队算法。

在设计Dictionary对象时,主要是利用将字符串型Key值作为一个参数传递给Item
的方法来实现对数据的访问,这一点与Collection对象相似,例如,你可以利用:

VItem = oDictionary.Item(sKey)


这儿警告一句,如果试图利用一个并不存在的键值返回Collection成员的数值,
将会出错(code 5, Invalid Procedure Call or Argument)。Dictionary对象
并不这样,它在插入该新成员时,采用并不存在的键值对应某个键同时用零长度
字符串对应数据成员。Dictionary对象总是检查你要使用的键是否存在于字典内
,可以想象,这一特点能够轻易地捕捉不经意所犯的错误,至于检查键值存在性
的方法将在本文的后续内容中述及。


当使用Collection对象时,你不能直接顺序地访问字典中的数据,但是使用字典
的Item方法时就不这样,你能够快速地创建所有数据成员的数组,并利用该数组
顺序地访问所有数据:
Dim vItems As Variant
Dim iOrdinal As Integer

iOrdinal = 10
vItems = oDictionay.Items
vItem = vItems(iOrdinal)

从Collection对象中删除数据的方法通常是采用For…Each…Next语句,在你初次
对Dictionary对象使用For…Each…Next时,可以假设你从未对字典使用过该语句
,但是尽管没有当前的记录位置,你仍能够使用For…Each…Next,你只需要
Dictionary对象的inter_NewEnum函数返回的与条目有关的键值,而不是象
Collection对象那样,需要返回字典条目的索引,你可以将这些键值传递给Item
方法以便删除数据成员,如下所示:
Dim sKey As Variant

For Each sKey in oDictionary
VItem = oDictionary.Item(sKey)

Next

当你在封装类中利用Dictionary对象时,存在另一个使用For…Each…Next的次要
关键。你不能在客户端使用For…Each…Next循环对数据成员进行迭代搜索,除非
你愿意进行大量的复杂编程。其原因是Dictionary对象的internal_NewEnum函数
不是一个隐含成员,而在Collection对象中它是,它不能通过Visual Basic调用
,因此你不能够在封装类实现自己的_NewEnum函数,简单的Set NewEnum =
mCol.[_NewEnum]语句不能与Dictionary对象共同工作,但是,使用Dcitionary对
象获得的诸多好处使这种折中非常值得。

那么,怎样访问Dictionary对象封装类的每一个成员呢?Dictionary对象包含名
为Items的方法,该方法返回所有Dictionary对象成员的一个可变数组,你只需要
在自己的类中提供一个封装子程序以返回Item数组:

Public Property Get Items() As Variant
Items = mdDict.Items
End Property

或者你愿意提供一个更加有意义的名字给封装特性,那么可以这样:
Public Property Get Employees() As Variant
Employees = mdDict.Items
End Property

然后你的客户端程序代码就可以利用For…Each…Next或For…Next循环在可变数
组中进行迭代搜索,以下这些代码告诉你怎样才能实现这一点:

Dim oEmployees As Employees ' wrapper class
Dim aEmployees As Variant ' Variant to hold array
Dim oEmp As Employee ' data member class
Dim i As Integer ' simple counter

Set oEmployees = New Employees 'Dictionary wrapper class
aEmployees = oEmployees.Employees 'return an array of objects

For i = lBound(aEmployees) To uBound(aEmployees)
Set oEmp = aEmployees(i)
cboNames.AddItem oEmp.Name
Set oEmp = Nothing
Next i
Set oEmployees = Nothing

那么性能怎样呢?当在同样的机器上调用动态连接库时,结合Dictionary封装类
的Item数组和Foe…Each…Next的迭代搜索不如仅仅运用Collection封装类进行的
迭代搜索快,但是如果你处理的是远程或进程外的服务程序,那么情况刚好相反
。利用Dictionary的封装类,你只是进行简单数组的简单转换,而Collection类
则反复调用远程服务程序,每一个迭代都要进行过程调用。

我设置了一个简单的实验以考察远程Dictionary对象和Collection对象的迁移性
,这些对象包括1000个简单的字符串成员并利用它们迁移一个客户端Form的列表
,Dictionary对象迁移该列表只需要四分之一秒,而Collection对象迁移该列表
则耗费了差不多三秒钟。

你的成员存在吗?
我反复抱怨Collection对象的一个因素是其没有能力让你预先知道Collection对
象的某一个成员是否存在,如果该成员的键值并不存在,那么你就不得不处理出
现的错误。由于这个原因,我通常利用一个类来封装我的Collection对象成员,
并使它们包括Exists属性。

不管怎样,Microsoft使Dictionary对象具有Exists方法。Exists非常便于使用,
并返回True或False,如下所示:

If oDictionary.Exsits(sKey) Then
' The key is there .
vVal = oDictionary.Item(sKey)
Else
MsgBox "The key doesn't exist"
End If

由于Dictionary对象总是为成员添加一个键值和一个空字符串,所以当你试图返
回一个并不存在键值的条目时,你总是能够在返回该条目之前利用Exists方法来
检测它的存在性(如上面例子所示),这个特点使你免于直接访问一个并不存在
的键值。

键值覆盖
如果你曾经试图改变某个与Collection对象成员对应的键值,那么你知道这不可
能。当对象成员加入到Collection对象时,该成员的数据和键值就已经被固定下
来了。你能做的唯一选择就是使用Remove方法清除该成员并增加一个新成员到该
对象。但是,你能够利用Dictionary对象的Key特性来覆盖该键的键值,如下例所
示:

If oDictionary.Exists(sOldKey) Then
' The key is there .
oDictionary.Key(sOldKey) = sNewKey
Else
MsgBox "The key dosen't exsit"
End If


成员覆盖
我猜想Microsoft在编制Collection对象时,他们假设Collection对象的成员一旦
加入就不再改变,他们为什么会认为开发人员仅仅与静态数据打交道呢?!因此
,改变Collection对象成员的唯一办法就是先从Collection对象中删除它们并重
新加入。

与Key特性相似,你能够利用存在于表达式两边的Dictionary对象的Item特性。在
一个表达式的右边,你返回对象成员的值,而在表达式的左边,你可以设置成员
的值,方法如下:

If oDictionary.Exists(sKey) Then
' The key is there .
oDictionary.Item(sKey) = vNewItem
Else
MsgBox "The key doesn't exist"
End If


补充
当你需要字典内所有键值的数组时,Item方法和Key方法也能够帮助你。Item方法
可以返回包含字典内所有数据成员的可变数组,而Key方法则可以返回包含字典内
所有键值的可变数组。 Dictionary对象的其他特性包括返回字典内成员数目的
Count特性和能够让你控制内部搜索执行情况的CompareMode特性,还有Remove特
性和RemoveAll特性,正如其名字所示,它们用于清除字典内的数据成员。


总结
Dictionary对象与Collection对象相比,是一个非常有价值的尝试。它不但速度
快,而且具有许多特性,使你从原来不得不自己编制封装类的烦恼中解脱出来。
虽然用Dictionary对象替换Collection对象还需要一些次要的记录技术(根据For
…Each…Next等而定),但是利用Dictionary对象所带来的性能上的提高足以补
偿这些努力。本专题的PROFESSIONAL RESOURCE CD包含一个例子类,从而向你展
现怎样围绕Dictionary对象创建一个名为DictCLass.CLS的封装类,它还包括一个
例子应用程序,该例子向你展示怎样利用这些类来获得超出于你应用程序的强大
功能。

Collection相当普及,大部分Visual Basic数据类都源于此类,而Dictionary对
象是重要的改进,在添加和删除对象成员方面要比Collection对象快三倍,你能
够戏剧性地提高应用程序的性能。你也可以自己进行Dictionary对象和
Collection对象的性能测试比较,你会得到与我大致相同的结果。


如果我可以自由选择(我的客户有足够的时间和金钱),那么我将用Dictionary
对象替换所有的Collection对象。这项工作还没有开始,至少本周不会进行,但
是从现在开始,我用Visual Basic 编制的所有程序都将采用Dictionary对象。





--

   好好学习,天天向上!!!!

※ 来源:·BBS 荔园晨风站 bbs.szu.edu.cn·[FROM: 192.168.11.111]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店