在为数组指定范围时显式和隐式使用ActiveSheet

时间:2015-04-15 10:08:48

标签: arrays vba excel-vba range excel

在考虑@Crouzilles问题时:Assigning range to array in VBA我意识到ActiveWorkbook.ActiveSheet是否明确用于定义范围至关重要。例如:

Dim arr1() As Variant
Dim arr2() As Variant

arr1 = Range("A1:B2")
arr2 = ActiveWorkbook.ActiveSheet.Range("A1:B2")               'Type mismatch

我曾假设两个右侧都会返回一个Range对象,这会被转换成一系列变体;但是,第二行会生成类型不匹配错误:

Run-time error '13': Type mismatch

为确保两个语句确实返回一个数组,我检查了TypeName()

Debug.Print TypeName(Range("A1:B2"))                            'Range
Debug.Print TypeName(ActiveWorkbook.ActiveSheet.Range("A1:B2")) 'Range

我还检查了Range("A1:B1").Worksheet.Name属性,以确保Range("A1:B2")确实是对ActiveWorkbook.ActiveSheet的引用。参考

然后我尝试将Range().Value分配给数组,这两个变体都正确执行:

arr1 = Range("A1:B2").Value
arr2 = ActiveWorkbook.ActiveSheet.Range("A1:B2").Value          'No error

这是有道理的,因为.Value会将Range对象转换为变体数组....与arr1arr2的类型相同:

Debug.Print TypeName(Range("A1:B2").Value)                      'Variant()
Debug.Print TypeName(ActiveWorkbook.ActiveSheet.Range("A1:B2").Value)   'Variant()

为了增加我的困惑,明确地将两个变体分配给Range引用允许分配两个数组:

Dim rng1 As Range
Dim rng2 As Range

Set rng1 = Range("A1:B2")
Set rng2 = ActiveWorkbook.ActiveSheet.Range("A1:B2")

arr1 = rng1
arr2 = rng2                                                     'No error

有人可以解释为什么Range引用的Range("A1:B2")对象可以隐式转换为变体数组而ActiveWorkbook.ActiveSheet.Range("A1:B2")不能吗?

1 个答案:

答案 0 :(得分:4)

它与绑定和默认属性的使用有关。 Activesheet返回一个对象,而不是Worksheet,因此之后的所有内容都是后期绑定的,而Range(...)实际上是Application.Range的简写,因此它的早期绑定。如果您声明工作表变量并为其分配ActiveSheet,则代码也将起作用:

Dim ws As Worksheet
Set ws = ActiveWorkbook.ActiveSheet
arr2 = ws.Range("A1:B2") ' works

将变量声明为Variant而不是Variant()也可以。

故事的道德:总是指明你的意思!

来自VBA语言规范:

5.6.2.3默认会员递归限制

如果返回的对象具有另一个默认成员,则对其默认属性Get或默认函数返回另一个对象的对象的评估可以导致递归评估过程。如果评估一个简单的数据值并且每个默认成员都有一个空参数列表,那么通过这个默认成员链的递归可能是隐式的,如果指定了专门参数化每个默认成员的索引表达式,则可以显式递归。

实现可以定义这种递归默认成员评估何时有效的限制。限制可能取决于诸如递归的深度,空参数列表的隐式与显式规范,成员是否返回特定类与返回Object或Variant,默认成员是函数还是Property Gets以及是否表达式发生在赋值的左侧。 实现可以确定这样的评估是静态无效的,或者可以在运行时评估期间引起错误9(下标超出范围)或13(类型不匹配)