You normally instantiate a CDO library object by accessing a property on a parent object that causes the desired object to be created. For example, the statement
Set objMsg = objSession.Inbox.Messages.Item(1)
instantiates a Folder object for the Inbox property of the Session object, then a Messages collection object for the Messages property of the Inbox folder, and then a Message object for the Item property of the Messages collection.
Every time you cross a period from left to right, you instantiate the object on the right of the period. This is true whether or not you have previously instantiated another version of the same object. This code fragment, for example, is intended to count the members of an AddressEntries collection that can resolve the name "John":
Dim objAdrList As AddressList
Dim objAEFilt As AddressEntryFilter
Dim objAE As AddressEntry
...
Set objAEFilt = objAdrList.AddressEntries.Filter
objAEFilt.Name = "John" ' set filter to restrict on this name
i = 0
For Each objAE in objAdrList.AddressEntries
i = i + 1
MsgBox objAE.Name
Next
As written, however, this code counts every AddressEntry object in the collection. This is because the collection itself is instantiated twice, once when setting the filter and once when initializing the loop, in response to the code objAdrList.AddressEntries
. The second collection is instantiated with a default AddressEntryFilter object with no restrictions, which is used in the loop. The filter with the Name property restriction remains with the first collection and is never used.
This behavior is counterintuitive to programmers accustomed to having the same object returned by repeated references. But no variable is defined for an object that is generated internally by crossing a period, and Visual Basic has no way of correlating its internal objects. It is up to you to take care of the correlation at the source code level.
The proper approach is to define and Set a variable for any object you plan to use more than once. In the case of the previous code fragment, it is the AddressEntries collection object that is to be reused:
Dim colAddrEntries As AddressEntries
...
Set colAddrEntries = objAdrList.AddressEntries
Set objAEFilt = colAddrEntries.Filter
objAEFilt.Name = "John" ' set filter to restrict on this name
i = 0
For Each objAE in colAddrEntries
i = i + 1
MsgBox objAE.Name
Next
C/C++ programmers should observe that the period in Visual Basic is not a class member access operator, nor is it a pointer. Although objAdrList.AddressEntries
may appear analogous to a construction such as lpAdrList->AddressEntries
, there is in fact very little parallelism between the two, and access to a property in C/C++ requires more than a single statement.
When you instantiate an object multiple times, you subject your application to several problems:
The safest procedure is to use explicit variables for all the objects and collections in your application. The consequence of not doing so can vary from inefficient execution to wrong results. For more information, see Improving Application Performance.