腳本語言有技術限制,他們只能使用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