【发布时间】:2014-10-24 05:00:30
【问题描述】:
我刚刚发现我可以使用可以创建 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 的 cmets,我能够让它工作并认为我会添加代码:
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
【问题讨论】:
-
您是否尝试过使用类似这样的额外方法从 ArrayList 创建派生类:
[DispId(-4)] public IEnumerator GetMyEnumerator() { return GetEnumerator(); },并获取 MyEnumerator 而不是 GetEnumerator? -
@SimonMourier VBA 不支持继承。恐怕你不能从其他类派生。
-
我说的不是VBA 方面,而是.NET 方面。此外,将 ComVisible(true) 属性添加到新的派生类。
-
你帮的太多了。 System.Collections.IEnumerator 会自动映射到 COM 枚举器 (IEnumVARIANT)。只需公开一个返回 IEnumerator 的方法(在其实现中调用 GetEnumerator),您就可以设置为 For Each。
-
@HansPassant 是的,您是对的,IEnumerable 接口具有正确的 COM 设置。但是,使用上述方法调用 GetEnumerator 失败。请参阅上面的编辑代码。
标签: .net vba for-loop arraylist com