试图理解在Range对象上使用Item属性和Cells属性之间的区别

Gee*_*aky 1 excel vba

我明白:

  • Range.Item 返回一个Range对象,该对象表示偏移到指定范围的范围.

  • Range.Cells 返回一个Range对象,该对象表示指定范围内的单元格.

但是,当我读到"Item是Range对象的默认属性"时,会出现混淆.

这让我想问:

Range("A1:D5").Cells(1,1)真正的简化版本 Range("A1:D5").Cells.Item(1,1)

为什么不在Range("A1:D5").Item(1,1)任何情况下使用?

为什么VBA程序员似乎使用该Cells属性来引用范围而不是Item属性?仅仅省略Item默认属性是"最佳实践" Cells吗?

Mat*_*don 5

Range是一个班级.类是蓝图对象 -一个对象是一个实例类的.

现在,VBA中的类可以具有默认属性.如果导出类模块,则可以为其提供成员属性.VB_UserMemId具有值的属性0将成员标识为该类的默认成员 - 您无法直接在VBE中编辑成员属性,但可以导出模块,添加属性并将模块重新导入项目.

一个默认的属性可能是这个样子:

Option Explicit
Private mFoo As Bar

Public Property Get Foo() As Bar
    Attribute Foo.VB_UserMemId = 0
    Set Foo = mFoo
End Property
Run Code Online (Sandbox Code Playgroud)

VB_UserMemId您可以使用许多可能的值,但只有一个类的一个成员可以具有任何给定值 - 0使其成为该类的默认成员.

默认成员允许您编写隐式代码 - 这是否是一件好事是判断调用.

例如,当您想要访问索引i为a 的项时Collection,可以执行以下操作:

foo = myCollection.Item(i)
Run Code Online (Sandbox Code Playgroud)

但由于Item是在默认属性中的Collection类,你也可以这样做:

foo = myCollection(i)
Run Code Online (Sandbox Code Playgroud)

结果完全一样.

Range堂课是......一种特殊的动物.如果你在对象浏览器中查看它的定义,你会发现它的默认属性是一个名为的隐藏属性_Default,通常推断为返回Range.Value- 因为这个隐式的默认成员调用:

foo = Sheet1.Range("A1")
Run Code Online (Sandbox Code Playgroud)

相当于这个显式代码:

foo = Sheet1.Range("A1").Value
Run Code Online (Sandbox Code Playgroud)

类的Item属性不是默认成员.但是,如果您查看该隐藏属性的定义,您将看到它接受两个可选参数:Range_Default

属性_Default({RowIndex},{ColumnIndex})

所以这也是合法的:

foo = Sheet1.Range("A1:A10")(1)
Run Code Online (Sandbox Code Playgroud)

相当于:

foo = Sheet1.Range("A1:A10").Item(1).Value
Run Code Online (Sandbox Code Playgroud)

基本上,Range类的默认属性是以如下方式实现的:如果没有指定参数它会做一件事(给你Value自己返回单元格的值,或者如果范围包含多个单元格则返回2D变体数组),如果指定了参数,另外一件事(Item在该范围内给出指定的行/列).

所以这就是为什么Range("A1:A10").Cells(没有参数)是多余的:它产生与完全相同的单元格Range("A1:A10").

Cells属性未参数化:

属性单元格作为范围

因此,VBA程序员Range.Cells使用参数调用,实际上是Range._Default使用这些参数调用,而不是Cells... 返回...这意味着Range("A1:A10").Cells(1)有效Range("A1:A10").Cells.Item(1)...这涉及到冗余调用Cells.

因此参数化Cells[._Default][.Item](1)语法仅仅是方便; 它主要是一个可读性的东西......然后就是IntelliSense:Item返回一个Variant,这意味着当你.在它之后键入点/解除引用运算符时,你没有得到可用成员的那么好的小下拉(调用是"后期绑定",即所涉及的类型在运行时被解析 - 但是你在调用时会这样做Cells,因为它Cells返回一个早期绑定的Range对象(即在编译时解析).

最佳实践是编写完成所述内容的代码,并说出它的作用 - 因此您通常希望避免隐式默认成员调用.但是,如果Range这与另一个最佳实践冲突,即尽可能编写编译时验证的早期绑定代码 - 使用Cells而不是Item给你.