Why can one iterate an ArrayList
using For Each
but not a Hashtable
?
Dim i
For Each i In CreateObject("System.Collections.ArrayList") ' no error
Next
For Each i In CreateObject("System.Collections.Hashtable") ' error
Next
Iterating the HashTable
gives
Object doesn't support this property or method.
Scripting languages have a technical limitation, they can only use the default interface of a coclass. They have no notion of interfaces at all and no back-door to obtain another interface through IUnknown::QueryInterface(). Like you can in C# by casting to the desired interface type. The iterator for ArrayList looks like this:
IEnumerator is the default interface, you have no problem using it from your VBScript. However, the enumerator for Hashtable looks like this:
IDictionaryEnumerator is the default, not IEnumerable. So VBScript cannot find the required Current and MoveNext members. Only Entry, Key and Value, they are useless. Much the same for the Keys and Values collection:
Same problem, CopyTo, Count, IsSynchronized and SyncRoot are useless. Microsoft could have very easily fixed this problem by applying the [ComDefaultInterface] attribute to these classes. But they didn't.
This can be worked around. What is required is code that can QI the default interface to obtain the IEnumerable interface. You can help with a wee C# class library project:
Build and register the assembly with both the 32-bit and 64-bit version of Regasm. Now you can make this script work:
Output: