Excel VBA:为什么"Sheets"集合不是"Collection"?

fre*_*oft 4 collections polymorphism excel inheritance vba

关于Excel VBA的一个简单问题:如果"Sheets"对象是一个集合,为什么下面的句子返回false?(在中级面板中输入)

debug.print TypeOf Sheets Is Collection
Falso
Run Code Online (Sandbox Code Playgroud)

我发现它是因为我创建了一个以Collection作为参数的函数.该函数适用于我声明为Collection的变量,但不适用于其他集合(例如Sheets集合).

也许VBA失败的继承和/或多态?


编辑:正如JosieP和mehow所解释的那样,Sheets集合不会继承Collection类/接口,因此它不是Collection,也不能以多态方式用作Collection.

所以现在的问题是:为什么Sheets不是Collection的子类?为什么他们没有继承Collection?鉴于已经在Sheets中实现的方法/属性,它应该是小菜一碟.我可以看到,Collection类/接口只需要4个方法:

Add
Count
Item
Remove
Run Code Online (Sandbox Code Playgroud)

而Sheets已经实现了4个类似的方法/属性:

Add
Count
Item
Delete
Run Code Online (Sandbox Code Playgroud)

因此映射将是微不足道的.他们可以轻松地将Sheets集合转换为Collection.


编辑2:我感谢mehow关于询问MS的建议,但我不会这样做,因为他们可能会说"这不是设计错误,它是一个功能":).更多思考的食物:在新工作簿中运行以下代码:

Sheets.Add.name = "sh2"
Sheets.Add.name = "sh3"

Dim col As Collection
Set col = New Collection
col.Add Sheets(1)
col.Add Sheets(2)
col.Add Sheets(3)

For Each ele In col
    Debug.Print "ele in col:  " & ele.name
Next ele

For Each ele In Sheets
    Debug.Print "ele in Sheets:  " & ele.name
Next ele
Run Code Online (Sandbox Code Playgroud)

我很奇怪,"col"和"Sheets"都可以以相同的方式迭代,使用"for each"循环,但它们不共享一个公共接口.如果我必须设计类,层次结构将是:

    iIterable       (interface)
        |
        |
    iCollection     (interface)
       / \
      /   \
     /     \
Collection  cSheets    (classes)
Run Code Online (Sandbox Code Playgroud)

和Sheets将是cSheets类的对象(实例).

通过这种方式,我创建的函数(当前采用Collection参数)将采用iCollection参数,因此它既可以使用Collection实例,也可以使用Sheets.

小智 6

SheetsObject类型的集合,而不是类型的对象Collection.

就像JosieP说的那样

Sheets类不从VBA Collection继承,也不实现Collection接口(例如,没有Remove方法)

应该足以理解.

MSDN参考

在此输入图像描述

Sub Main()

    Dim c As Collection
    Set c = New Collection

    Debug.Print VarType(c), TypeOf c Is Collection

    Debug.Print VarType(Sheets), TypeOf Sheets Is Object

End Sub
Run Code Online (Sandbox Code Playgroud)

为了确认打开Object BrowserF2和类型找到Sheets


向Microsoft提出第二个问题.但是请记住,Collection可以是空的,而Sheets总是需要至少有一个Sheets或Chart对象.

很多东西都依赖于Excel中的Sheets集合对象,这就是为什么我认为它必须是一个单独的类.通过实现ICollection接口并提供单独的实现,我看不出有什么问题,但就像我说的那样问微软(好问题)


for each循环是可能的,因为每个VBA类有属性.并非所有属性都可以通过IDE看到,但它们确实存在(更多的VB6常识而不仅仅是对VBA的引用).

好的,现在回答你的第三个问题.您可以遍历集合,因为它实现了IUnknown接口NewEnum()(可启动方法).您在类型集合上指定默认迭代对象(在表格案例中为其Sheets集合).

有关可枚举方法的更清晰说明,请参阅此链接.

请参阅此答案以更好地了解迭代是如何实现的.

  • + 1另外一种方法是使用`Watch` Window :) (4认同)
  • 集合也是一个对象,所以我不确定这证明了什么?`typeof c is object`也返回True (2认同)
  • 我知道:)我的观点是你的代码似乎没有证明什么,因为`typeof c is object`也返回True,就像`typeof Sheets is object`一样.最初的`typeof Sheets is Collection`实际上已经证明了我的意思 (2认同)