用自定義 VBA 類包裝 .Net ArrayList 獲取迭代器
我剛剛發現我可以使用可以創建 COM 類的 CreateObject 方法從 VBA 創建一些 .Net 類。這很酷,但是創建的類是後期綁定的,所以你不會得到任何智能感知等。所以我希望做的是編寫 VBA 包裝類並將所有方法呼叫委託給 .Net 對象的內部引用。
所以這對於一個 ArrayList 對象來說很好,除了試圖引用列舉器之外。VBA 有一個 hack,它允許您創建自己的集合併使用 For Each … 語法來列舉您的集合。下面是一個例子:
Public Property Get NewEnum() As IUnknown Attribute NewEnum.VB_UserMemId = -4 Attribute NewEnum.VB_MemberFlags = "40" Set NewEnum = <<< pass a reference to the enumerator here. End Property大多數實現都持有對 VBA Collection 對象的引用,並傳遞 Collection 對象的列舉器。但是,由於我持有一個 .Net ArrayList,我想將其傳遞出去。但是,當我嘗試時,我得到“無效的過程呼叫或參數”。
我目前的嘗試是這樣的:
Public Function NewEnum() As IUnknown Dim enumerator As Object Set enumerator = internalList.GetEnumerator() <<<< Error occurs here. Set NewEnum = enumerator End Function我很確定它可以完成這項工作,因為可以在沒有包裝器的情況下直接迭代 ArrayList 集合。例如
Public Sub TestCreateArrayList() Dim list As Object Set list = CreateObject("System.Collections.ArrayList") list.Add "an item." list.Add "another item." Dim Item As Variant For Each Item In list Debug.Print Item Next End Sub我可以在沒有 For Each 功能的情況下生活,但如果我能讓它工作,尤其是當它看起來幾乎就在那裡的時候,那就太好了。
編輯:可能值得一提的是,實例化 ArrayList 然後呼叫 GetEnumerator 會產生相同的錯誤,即使在包裝類之外也是如此。
進一步編輯:請注意,嘗試將 IUnknown 類型的變數設置為 GetEnumerator 方法的結果仍然會產生相同的錯誤。
Public Sub TestCreateArrayList() Dim list As Object Set list = CreateObject("System.Collections.ArrayList") Dim iterator As IUnknown Set iterator = list.GetEnumerator() <<<< error occurs here. End Sub最終編輯:感謝@RegEdit 下面的評論,我能夠讓它工作並認為我會添加程式碼:
Private internalList As Object Private Sub Class_Initialize() ' create a .Net Array list for the internal data store. Set internalList = CreateObject("System.Collections.ArrayList") End Sub Private Sub Class_Terminate() If Not internalList Is Nothing Then On Error Resume Next internalList.Dispose Err.Clear End If End Sub Public Function NewEnum() As IUnknown Attribute NewEnum.VB_UserMemId = -4 Dim enumerator As IUnknown Set enumerator = internalList.GetEnumerator(0, internalList.Count) Set NewEnum = enumerator End Function ' ... other wrapped methods elided
當你使用
Dim enumerator As Object您正在聲明一個 COM 對象。但是 COM 將 IEnumerator 實現為
IEnumVARIANT,它直接繼承IUnknown,並且 COM 不樂意嘗試將GetEnumerator返回值設置為Object. 相反,您可以使用Dim enumerator As IEnumVARIANT**編輯:**請注意,雖然
ArrayListimplementsIEnumerable,但它使用採用and的方法重載GetEnumerator。所以當你想呼叫不帶參數的重載時,你必須在 VBA 中使用關鍵字。index``count``NothingSet iterator = list.GetEnumerator(Nothing, Nothing)您可以看到它正在工作,因為如果您包含將兩個項目添加到列表中的原始程式碼行,然後使用諸如
Set iterator = list.GetEnumerator(1, 3) ' 3 is out of bounds您現在收到一個新的(預期的)錯誤,通知您偏移/長度超出範圍。