Reputation: 2526
I started using Collection
in VBA (Excel AddIn --> xlam), but find it quite hard to use. I cannot retrieve anything I put into, other then Variants. In Java for example, if you make a Collection
, you assign a type to it, like Collection<MyPerfectObjectThatStoresSomeData>
, so when I foreach it, I know I get my object back and can use it like that. When I would like to do the same in VBA, I get back Variant
types and I can't even cast it to my type.
Example.
Let's say I would like to get the last entry from the Collection
I fill up like this:
Private Function FindTargets(sheet As Worksheet, target As String) As Collection
Dim result As New Collection
Dim aCell As range
Dim i As Long
For i = 1 To 10456
Set aCell = sheet.Rows(i).Find(What:=target, LookIn:=xlValues, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not aCell Is Nothing Then
MsgBox "Value Found in Cell " & aCell.Address & _
" and the Cell Column Number is " & aCell.Column
result.Add aCell
End If
Next i
Set FindTargets = result
End Function
After, I would like to loop through the results, but I cannot event get the last entry out without an error:
Dim targetCollection As Collection
Set targetCollection = FindTargets(targetSheet, "some text")
Dim target As range
target = targetCollection.Item(targetCollection.Count - 1)
I get the error:
Run-time error '91':
Object variable or With block variable not set
If I try
Set target = targetCollection.Item(targetCollection.Count - 1)
I get:
Run-time error '1004':
Application-defined or object defined error
Can I only loop and get entries from a Collection
into other than Variant
types?
Edit: To be more specific, this code would need the range's coordinates, but in a Variant
I get the text of the cell. I thought about making a new Class, like CellProperties
with properties to both text and coordinates and put this into the Collection, but again, I cannot retrieve anything other than Variant from a Collection
.
Upvotes: 1
Views: 5844
Reputation: 14053
VBA-Collection is data structure which can contain heterogeneous objects. So unlike Collection Of MyPerfectObjectThatStoresSomeData
where the collection ensures that object of certain data type can be added into, in VBA-Collection
we can store anything in the collection so it can contain heterogeneous object types at the same time. But in your case the collection actually contains objects of type Variant\Object\Range
. This means it contains objects of type Variant
and sub-type Range
. VBA-Collection
can be enumerated and it hast Item
method which can be used to acces items of the collection where the first item hast index of 1
.
In you case you can do e.g. this:
targetCollection.Add "Banana"
targetCollection.Add ActiveSheet
targetCollection.Add Excel.Application
Dim itm As Variant
For Each itm In targetCollection
If TypeName(itm) = "Range" Then _
Debug.Print itm.Address
Next itm
To get the last element safely (in case the last element is of type Range
):
Dim lastElement As Range
If targetCollection.Count > 0 Then _
Set lastElement = targetCollection.Item(targetCollection.Count)
As a side note: why not use Dim As New.
Upvotes: 1
Reputation: 23974
It appears that your error is caused by assuming a Collection's items are zero-based, but the first item in a Collection
has an index of 1
Below is a cut down version of your FindTargets
which I used for testing, and a test subroutine that returns the Address
of the last cell added to the Collection
:
Private Function FindTargets(sheet As Worksheet, target As String) As Collection
Dim result As New Collection
Dim i As Long
For i = 1 To 100
result.Add Cells(i, 1)
Next i
Set FindTargets = result
End Function
Sub test()
Dim targetCollection As Collection
Set targetCollection = FindTargets(Worksheets("Sheet1"), "some text")
Dim target As Range
Set target = targetCollection.Item(targetCollection.Count)
MsgBox target.Address 'will display $A$100
End Sub
Upvotes: 4