Dim hashData As Object
Set hashData = obj.getHashData
If getHashData
is returning a HashTable
, then hashData
is a late-bound HashTable
, and you can invoke its members, including its Item
property:
Dim value As Variant
value = hashData.Item("key")
You're not getting compile-time validation on the late-bound member calls against Object
, so you need to be particularly careful for typos, because Option Explicit
cannot save you when late binding is involved. Refer to the HashTable
documentation linked above for what members you can invoke.
Adding a reference to mscorlib.tlb
(you'll find it under C:\Windows\Microsoft.NET\Framework\v4.0.30319
, or reference the equivalent from \Framework64
if your Excel is 64-bit - bitness of the library needs to match the bitness of the host application) would normally allow for early binding, but while this library is COM-visible, it's intended to be used from managed (.net) code, so you're accessing these objects from interfaces - the concrete types don't expose any members directly:

Knowing that Hashtable
implements the IDictionary
interface, we can use early binding and get compile-time validation and IntelliSense if we declare hashData As IDictionary
:
Dim hashData As mscorlib.IDictionary
Set hashData = New mscorlib.Hashtable
hashData.Add "foo", 42
Debug.Print hashData.Item("foo") 'prints 42
Note that the Item
property is exposed as the default member:

This means you can have the Item
member call implicit, exactly as you could do with any standard VBA collection object:
Dim hashData As mscorlib.IDictionary
Set hashData = New mscorlib.Hashtable
hashData.Add "foo", 42
Debug.Print hashData("foo") 'prints 42
Early-bound code is much easier to write, especially when you're not familiar with the types involved. However if the project is referencing the 64-bit framework and your macros need to run on 32-bit Excel, you'll want to stick to late binding to avoid binding issues.
Also note, iterating the Hashtable
object with a For Each
loop isn't going to work, because of how enumerators work in VBA vs how they work in .NET; the Keys
and Values
collections are objects implementing the ICollection
interface, so iterating them will be non-trivial as well: a For Each
loop won't work, and while you can set up a For i = 0 To hashData.Keys.Count - 1
, you can't get the item at index i
from an ICollection
.
But we know that ICollection
inherits IEnumerable
, and IEnumerable
does work with For Each
, so we can cast the Keys
collection to IEnumerable
, and iterate all keys and values like so:
Dim hashData As mscorlib.IDictionary
Set hashData = obj.getHashData
Dim hashKeys As mscorlib.IEnumerable
Set hashKeys = hashData.Keys
Dim k As Variant
For Each k In hashKeys
Debug.Print k, hashData(k) 'outputs the key and its associated value
Next
The problem is that you can't cast to IEnumerable
with late-bound code or without a reference to mscorlib.tlb
, and late binding somehow won't see the GetEnumerator
member, so this raises error 438:
Dim hashKeys As Object
Set hashKeys = hashData.Keys
Dim k As Variant
For Each k In hashKeys ' error 438, hashKeys isn't exposing the enumerator
Debug.Print k, hashData(k)
Next
Conclusion: if you need the VBA code to run on both 32 and 64 bit hosts, you'll have to jump through hoops to get late-bound code to work. I would recommend working early-bound with the 64-bit framework if you're on a 64-bit host, and distributing a separate copy of the macro that references the 32-bit framework for 32-bit hosts. A bit of a pain to distribute, but less painful than getting late bound code to work.