为什么使用`For Each`迭代Hashtable在VBScript中不起作用?

Mic*_*ann 4 .net com vbscript

为什么可以迭代ArrayList使用For Each而不是Hashtable

Dim i

For Each i In CreateObject("System.Collections.ArrayList") ' no error
Next

For Each i In CreateObject("System.Collections.Hashtable") ' error
Next
Run Code Online (Sandbox Code Playgroud)

迭代HashTable给出

Object不支持此属性或方法.

Han*_*ant 7

脚本语言有技术限制,它们只能使用coclass的默认接口.它们根本没有接口概念,也没有通过IUnknown :: QueryInterface()获得另一个接口的后门.就像你可以在C#中通过强制转换为所需的接口类型一样.ArrayList的迭代器如下所示:

private sealed class ArrayListEnumeratorSimple : IEnumerator, ICloneable {
   // etc...
}
Run Code Online (Sandbox Code Playgroud)

IEnumerator是默认界面,从VBScript中使用它是没有问题的.但是,Hashtable的枚举器看起来像这样:

private class HashtableEnumerator : IDictionaryEnumerator, IEnumerable, ICloneable {
   // etc..
}
Run Code Online (Sandbox Code Playgroud)

IDictionaryEnumerator是默认值,而不是IEnumerable.因此VBScript无法找到所需的Current和MoveNext成员.只有入门,关键和价值,它们都没用.键和值集合大致相同:

public class KeysCollection : ICollection, IEnumerable {
   // etc..
}
Run Code Online (Sandbox Code Playgroud)

同样的问题,CopyTo,Count,IsSynchronized和SyncRoot都没用.通过将[ComDefaultInterface]属性应用于这些类,Microsoft可以非常轻松地解决此问题.但他们没有.


这可以解决.所需要的是能够QI默认接口获取IEnumerable接口的代码.您可以帮助完成一个C#类库项目:

using System;
using System.Collections;
using System.Runtime.InteropServices;

namespace VBScript
{
    [ComVisible(true), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    public interface IMapper {
        IEnumerable ToEnum(object itf);
    }

    [ComVisible(true), ProgId("VBScript.Mapper")]
    public class Mapper : IMapper {
        public IEnumerable ToEnum(object itf) {
            return (IEnumerable)itf;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

使用32位和64位版本的Regasm构建和注册程序集.现在你可以使这个脚本工作:

Set table = CreateObject("System.Collections.Hashtable")
table.Add 1, "one"
table.Add 2, "two"
Set mapper = CreateObject("VBScript.Mapper")
For Each key in mapper.ToEnum(table.Keys)
   WScript.Echo key & ": " & table(key)
Next
Run Code Online (Sandbox Code Playgroud)

输出:

Microsoft (R) Windows Script Host Version 5.812
Copyright (C) Microsoft Corporation. All rights reserved.

1: one
2: two
Run Code Online (Sandbox Code Playgroud)