VBA 字典与集合(Dictionary与Collection)_collection 对象有exists方法吗-程序员宅基地

技术标签: VBA  

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 DictionarySet 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 VariantDim iOrdinal As IntegeriOrdinal = 10vItems = oDictionay.Items
vItem = vItems(iOrdinal)从Collection对象中删除数据的方法通常是采用For…Each…Next语句,在你初次对Dictionary对象使用For…Each…Next时,可以假设你从未对字典使用过该语句,但是尽管没有当前的记录位置,你仍能够使用For…Each…Next,你只需要Dictionary对象的inter_NewEnum函数返回的与条目有关的键值,而不是象Collection对象那样,需要返回字典条目的索引,你可以将这些键值传递给Item方法以便删除数据成员,如下所示: Dim sKey As VariantFor Each sKey in oDictionaryVItem = 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 VariantItems =mdDict.ItemsEnd Property

或者你愿意提供一个更加有意义的名字给封装特性,那么可以这样:Public Property Get Employees() As VariantEmployees = mdDict.ItemsEnd Property然后你的客户端程序代码就可以利用For…Each…Next或For…Next循环在
可变数组中进行迭代搜索,以下这些代码告诉你怎样才能实现这一点:Dim oEmployees As Employees ’ wrapper classDim aEmployees As Variant ’ Variant to hold arrayDim oEmp As Employee ’ data member classDim i As Integer ’ simple counterSet oEmployees = New Employees ‘Dictionary wrapper classaEmployees = oEmployees.Employees ‘return an array of objectsFor i = lBound(aEmployees) To uBound(aEmployees)Set oEmp = aEmployees(i)cboNames.AddItem oEmp.NameSet oEmp = NothingNext 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)ElseMsgBox “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) = sNewKeyElseMsgBox “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对象的性能测试比较,你会得到与我大致相同的结果。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/yanlovehan/article/details/54097658

智能推荐

Redis 主从复制-哨兵-集群 相关部署_windows redis 主从复制部署-程序员宅基地

文章浏览阅读175次。Redis 主从复制+哨兵+集群一.主从复制-哨兵-集群二.主从复制1.主从复制的作用2.主从复制流程3.部署Redis 主从复制三.哨兵模式1.哨兵模式的原理2.哨兵模式的作用3.哨兵结构由两部分组成,哨兵节点和数据节点部署哨兵模式四.集群模式1.集群的作用,可以归纳为两点2.Redis集群的数据分片3.以3个节点组成的集群为例4.Redis集群的主从复制模型5.Redis集群部署一.主从复制-哨兵-集群1.主从复制:主从复制是高可用Redis的基础,哨兵和集群都是在主从复制基础上实现高可用的。主从复_windows redis 主从复制部署

看完还不懂HashMap算我输(附职场面试常见问题)_hashmap原理详解,看不懂算我输(附面试题)-程序员宅基地

文章浏览阅读1.3w次,点赞181次,收藏596次。HashMap的原理与实现版本之更迭:–》JDK 1.7 : Table数组+ Entry链表;–》JDK1.8 : Table数组+ Entry链表/红黑树;(为什么要使用红黑树?)一问HashMap的实现原理你看过HashMap源码吗,知道底层的原理吗为什么使用数组+链表用LinkedList代替数组可以吗既然是可以的,为什么不用反而用数组。重要变量介绍:..._hashmap原理详解,看不懂算我输(附面试题)

PHP实现跨域多图上传_php 上传图片流跨域怎么做-程序员宅基地

文章浏览阅读959次。干货:问题:在a.com上上传图片至b.comhtml(a.com)<div class="box_03"> <iframe style="width:100%;height:100%;" frameborder="0" scrolling="no" src="/picupload/ming?imgurl=&shuiyin=&uploadUr..._php 上传图片流跨域怎么做

Cisco(46)——HSRP和VRRP_hsrp 可以在svi口配置么-程序员宅基地

文章浏览阅读1.2w次,点赞4次,收藏2次。实验拓扑:实验说明:1.把SW3模拟成三台PC,配置三个VLAN对应的SVI地址。2.HSRP:SW1做vlan 10的活动设备,SW2做vlan 20的备份设备;SW1做vlan 10的备份设备,SW2做vlan 20的活动设备;3.VRRP:SW1做vlan 30的Master,SW2做vlan 30的备份设备。4.down掉环回口,检查数据包的路径。实..._hsrp 可以在svi口配置么

kafka-0.8.2.1-src编译报错解决办法_to honour the jvm settings for this build a new jv-程序员宅基地

文章浏览阅读8k次。今天编译kafka-0.8.2.1-src源代码,发现一个问题。编译始终报错,错误如下:lizhitao@users-MacBook-Pro-2:~/mt_wp/open_source/kafka-platform/kafka-0.8.2.1-src$ gradle jar_core_2_10_4 --stacktraceTo honour the JVM settings for this bu_to honour the jvm settings for this build a new jvm will be forked. please c

微信支付退款 java_Java后台实现微信支付和微信退款-程序员宅基地

文章浏览阅读600次。微信支付流程都是我自己工作中开发的,亲测可用,不喜勿喷。controller中我是这么写的,你们需要根据自己的业务需求改动。ResponseBean是我自己封装的,你们可以改成你们想要的形式。/*** 微信统一下单接口* @return*/@RequestMapping(value = "/doUnifiedOrder", method = RequestMethod.POST)public Re..._java+微信支付 dounifiedrefund

随便推点

PDO / MySQL:如何优化内存消耗大的结果集查询-程序员宅基地

文章浏览阅读140次。I'm having a strange time dealing with selecting from a table with about 30,000 rows.It seems my script is using an outrageous amount of memory for what is a simple, forward only walk over a query res..._pdo_mysql.cache_size

layui实现表格合并单元格,设置不同背景色_layui tablemerge 合并背景-程序员宅基地

文章浏览阅读1.0k次。最近在使用layui的过程中,遇到了表格合并单元格,设置不同底色的问https://www.hixiaoe.com/题。在此总结,大家一起学习。效果如下:同一组新闻的底色相同实现代码:<script> layui.config({ base: '/static/' //静态资源所在路径 }).extend({ index: 'admin/lib/index' //主入口模块 .._layui tablemerge 合并背景

kali2020.3详细安装教程|避免踩坑版_kali2020.3安装-程序员宅基地

文章浏览阅读3.8k次,点赞10次,收藏18次。Kali Linux系统作为白帽、黑帽最受欢迎的渗透测试系统,你如果是一个安全渗透专家或者网络安全管理员,必须要学会慎重并且合理地利用这个系统,因为对目标系统造成的实质伤害会带来法律的约束以及制裁!1、Kali Linux下载官网下载镜像:下载链接:https://www.kali.org2、安装配置我这里使用的虚拟机软件是 VMware 15,名字随便看需要,也可按默认配置建议选4G,也可以选2G内存默认,下一步默认,下一步默认,下一步默认,下一步这里建议将磁_kali2020.3安装

消息队列mysql redis那个好,redis可以做消息队列吗-程序员宅基地

文章浏览阅读131次。应用场景:例如秒杀。瞬时大量写入订单到数据库,导致数据库无法及时响应。此时可以采用Redis做消息队列,把所有需要写入的数据先写入Redis消息队列中,然后同时在服务器开启php-cli进程循环读取队列中的数据,异步写入数据库。使用redis做消息队列可能会出现消息丢失的情况,因为没有消息接收的确认机制。大型程序,应该使用类似RabitMQ来做专业消息队列。1、使用publish/subscrib..._mysql 做队列好还是redis做队列

linux环境安装apache服务器_no such command: nginx. please use /usr/bin/yum ---程序员宅基地

文章浏览阅读1.3k次。本文转自:https://www.cnblogs.com/wcwnina/p/8029156.htmlApache简介 Apache HTTP Server(简称Apache)是Apache软件基金会的一个开放源码的网页服务器,可以在大多数计算机操作系统中运行,由于其多平台和安全性被广泛使用,是最流行的Web服务器端软件之一。它快速、可靠并且可通过简单的API扩展,将..._no such command: nginx. please use /usr/bin/yum --help

LINUX-基础回顾_linux 粘贴之后 只做提示-程序员宅基地

文章浏览阅读560次。xShell:最常用的软件!远程操作linux,打开命令行终端!终端模拟软件。export LANG=“zh_CN.UTF-8” #中文export LANG=“en_US.UTF-8” #英文查看linux的ip地址:ifconfig;Linux无法使用ifconfig命令查看ip地址是因为没有安装net-tool所以执行下面的语句进行安装。_linux 粘贴之后 只做提示