如何在VBA中清空一个数组?

5
我正在开发一个Excel VBA插件,用于与COM服务器交换对象,类似于以下内容:
'get an array of objects
Dim Ents() As ISomething
ComObject.GetEntities Ents

'send an array with 10 objects
ReDim Ents(9)
Set Ents(0) = ...
...
ComObject.SetEntities Ents

获取数组效果很好:如果数组包含对象,则按预期工作,如果数组为空,则 UBound(Ents) = -1 并且一切都按预期工作。
发送数组仅适用于非空数组,因为我不能 Redim Ents(-1),并且删除 VBA 和 COM 服务器中的数组都会崩溃:Debug.Print UBound(Ents) 在 VBA 中崩溃,并且谁知道会导致服务器崩溃。
看起来像是 Erase 语句将数组变量定义/损坏而不是清空。
编辑(澄清下面的评论):执行此代码会崩溃,因为无法计算 UBound
Sub Test()
  Dim Ents() As ISmartId
  Debug.Print UBound(Ents)
End Sub

但是,如果您将Ents添加到监视窗口,然后设置断点到Debug.Print行并执行,调试器会在类型列中显示ISmartId(0 to -1)。之后,执行继续进行,而调试窗口显示了预期的-1
看起来,调试器能够正确地初始化我需要的空数组,以便显示其值。

我认为你不能这样做。据我所知,你只能擦除它们,然后在尝试测试其大小时捕捉错误。请看这里:https://dev59.com/1nVC5IYBdhLWcg3wtzgQ - RBarryYoung
@RBarryYoung:我可以在VBA端进行检查,但COM服务器是第三方应用程序,他们只期望一个空数组。我刚刚找到了一个解决方法,只适用于字符串数组:Split("")。我需要一个适用于IAnything的通用解决方案。这有助于您的想象力吗? - stenci
1
这对你的幻想有帮助吗?嗯?抱歉,我不明白...? - RBarryYoung
抱歉,我的意思是提醒一种完成工作的方法或者给你一个新技巧的想法。 - stenci
2个回答

4

针对对象,您可以通过将未定义的数组复制到 variant 中再复制回来来实现:

Dim o() As Worksheet
Dim v As Variant
v = o
o = v

对于非对象,可以在一个变体中创建一个空数组,然后更改其类型代码:
Private Declare Sub GetMem2 Lib "msvbvm60" (src As Any, dest As Any)

Dim i() as Long
Dim v as Variant
v = Array()

Dim NewTypeCode As Integer
NewTypeCode = vbArray Or vbLong
GetMem2 NewTypeCode, v
i = v

我接受了这个答案,因为它非常接近我所需要的,即使它没有给我想要的类型。我注意到,在观察窗口中有数组和Erase之后的断点时,VBA会将数组初始化为空数组,此时我可以继续执行并且它能正常工作。你知道那个观察窗口底层发生了什么吗? - stenci
你能发一下你正在运行的代码和断点在哪里吗?当你谈到“Erase”语句时,我有些难以理解你的意思。 - Chel
1
@stenci 好的,我已经更新了我的答案,提供了一个更为直接的早期绑定对象解决方案。 - Chel
现在我可以为所有的数组创建一个工厂。谢谢! - stenci
我在这个解决方案上遇到了问题。我发了另一个问题,请您能够看一下并找到解决方案。谢谢!https://stackoverflow.com/questions/48794596/creating-an-empty-array-in-vba - stenci

-1
如果您需要一个新的数组,您可以创建一个“工厂”函数来返回一个。
Function FreshArray() As ISomething()
   Dim rv() As ISomething
   FreshArray = rv
End Function

Ents = FreshArray() 
ComObject.GetEntities Ents

1
这个功能类似于“Erase”:创建一个损坏/未定义的数组。它在读取“UBound(FreshArray)”时崩溃。 - stenci

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接