关于 .net:为什么在 VBScript 中使用”For Each”迭代哈希表不起作用?

Why does iterating a Hashtable with `For Each` not work in VBScript?

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

1
2
3
4
5
6
7
Dim i

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

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

迭代 Hashtable 得到

Object doesn't support this property or method.


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

1
2
3
private sealed class ArrayListEnumeratorSimple : IEnumerator, ICloneable {
   // etc...
}

IEnumerator 是默认界面,您可以在 VBScript 中使用它。但是,Hashtable 的枚举器如下所示:

1
2
3
private class HashtableEnumerator : IDictionaryEnumerator, IEnumerable, ICloneable {
   // etc..
}

IDictionaryEnumerator 是默认值,而不是 IEnumerable。因此 VBScript 找不到所需的 Current 和 MoveNext 成员。只有Entry、Key和Value,它们是无用的。 Keys and Values 集合也差不多:

1
2
3
public class KeysCollection : ICollection, IEnumerable {
   // etc..
}

同样的问题,CopyTo、Count、IsSynchronized 和 SyncRoot 都没用。通过将 [ComDefaultInterface] 属性应用于这些类,Microsoft 可以很容易地解决此问题。但他们没有。

这可以解决。需要的是可以 QI 默认接口以获得 IEnumerable 接口的代码。你可以帮助一个小的 C# 类库项目:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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;
        }
    }
}

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

1
2
3
4
5
6
7
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

输出:

1
2
3
4
5
Microsoft (R) Windows Script Host Version 5.812
Copyright (C) Microsoft Corporation. All rights reserved.

1: one
2: two