Ros*_*sco 10 .net com vba for-loop arraylist
我刚刚发现我可以使用CreateObject方法从VBA创建一些.Net类,它可以创建COM类.这非常酷,但是创建的类是后期绑定的,所以你没有获得任何intellisense等.所以我希望做的是编写VBA包装类并将所有方法调用委托给.Net对象的内部引用.
因此,除了尝试引用枚举器之外,这适用于所有内容的ArrayList对象.有一个VBA的黑客攻击,它允许您创建自己的集合并使用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
Run Code Online (Sandbox Code Playgroud)
大多数实现都包含对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
Run Code Online (Sandbox Code Playgroud)
我很确定它可以实现这个功能,因为可以在没有包装器的情况下直接迭代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
Run Code Online (Sandbox Code Playgroud)
我可以在没有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
Run Code Online (Sandbox Code Playgroud)
最终编辑:感谢@ 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
Run Code Online (Sandbox Code Playgroud)
Reg*_*dit 11
当你使用
Dim enumerator As Object
Run Code Online (Sandbox Code Playgroud)
你正在声明一个COM对象.但是COM实现了IEnumerator IEnumVARIANT,它IUnknown直接继承,并且COM不乐意尝试将GetEnumerator返回值设置为Object.相反,你可以使用
Dim enumerator As IEnumVARIANT
Run Code Online (Sandbox Code Playgroud)
编辑:请注意,虽然ArrayList实现IEnumerable,它重载GetEnumerator了一个带index和的方法count.因此Nothing,当您想要在没有参数的情况下调用重载时,必须在VBA中使用关键字.
Set iterator = list.GetEnumerator(Nothing, Nothing)
Run Code Online (Sandbox Code Playgroud)
您可以看到它正在工作,因为如果您包含将两个项目添加到列表中的原始代码行,然后使用诸如
Set iterator = list.GetEnumerator(1, 3) ' 3 is out of bounds
Run Code Online (Sandbox Code Playgroud)
您现在得到一个新的(预期的)错误,通知您偏移/长度超出范围.