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对象的比较app
从Visual Basic 4.0开始,Collection对象就做为主要的数据类型替代了用户本身定义的类型,由此之后,大多数Visual Basic程序都包含Collection对象。若是你从Visual Basic 4.0开始已经很是习惯于使用Collection对象,那么你又为何须要做出改变呢?这主要有几个因素:函数
Dictionary对象比Collection 对象更快,这种速度优点主要体如今增长数据成员、在字典中进行迭代搜索和删除数据成员上。 性能
Dictionary对象包括那些你常常不得不本身编制的封装函数,例如Exists函数和RemoveAll函数。测试
Dictionary对象让你可以建立Key值数组和Item值数组,从而加快在字典中进行迭代搜索的速度。spa
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对象。
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对象。