脚本语言有技术限制,他们只能使用coclass的默认界面。他们根本没有接口的概念,也没有通过IUnknown :: QueryInterface()获得另一个接口的后门。就像你可以在C#中通过转换为所需的接口类型一样。 ArrayList的迭代器如下所示:
private sealed class ArrayListEnumeratorSimple : IEnumerator, ICloneable {
// etc...
}
IEnumerator是默认接口,从VBScript中使用它没有问题。然而,对于Hashtable的枚举看起来是这样的:
private class HashtableEnumerator : IDictionaryEnumerator, IEnumerable, ICloneable {
// etc..
}
IDictionaryEnumerator是默认的,不IEnumerable的。所以VBScript找不到所需的Current和MoveNext成员。只有入口,关键和价值,它们是无用的。对于Keys和Values集合也是如此:
public class KeysCollection : ICollection, IEnumerable {
// etc..
}
同样的问题,CopyTo,Count,IsSynchronized和SyncRoot都没用。微软通过将[ComDefaultInterface]属性应用于这些类可以很容易地解决这个问题。但他们没有。
这可以解决。需要的是可以使用默认接口获取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;
}
}
}
构建和两个Regasm的32位和64位版本注册程序集。现在,你可以使这个脚本工作:
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
输出:
Microsoft (R) Windows Script Host Version 5.812
Copyright (C) Microsoft Corporation. All rights reserved.
1: one
2: two
我猜Hashtable对象尚未建立与枚举支持。你可以用字典吗?您可以遍历一个Dictionary。 – eurotrash