Excel vba运行时错误424分配Rangevariables时需要的对象
我有这个代码包含一个函数和使用该函数的子例程。 函数将一列作为参数,并更改每个列单元格的内容。
Function testFunc(aCol As Range) Dim i As Integer i = 0 For Each cell In aCol cell.Value = i i = i + 1 Next End Function Sub testSub() Dim aRange As Range Set aRange = ThisWorkbook.Sheets("Sheet1").Range("A1:A16") testFunc (ThisWorkbook.Sheets("Sheet2").Range("A1:A16")) '<--- this works fine testFunc (aRange) '<---- error End Sub
Runtime error '424' Object required"| arises on line
testFunc(aRange)`出现。我不知道什么是错的,我通过”设置“分配variables,它应该工作正常。
另外,我试着将范围直接传递给函数,而不是首先将其存储在variables中,并且完美地工作。 为什么 ?
expression式周围的括号导致expression式被评估为一个值,并将ByVal
传递给被调用的过程。
testFunc (ThisWorkbook.Sheets("Sheet2").Range("A1:A16")) '<--- this works fine
不,它不能正常工作,而不是在testFunc
的签名中使用aCol As Range
,原因与其下面的行完全相同。 一个Range
对象有一个指向它的.Value
的默认成员 。 当你这样做:
DoSomething (SomeRange)
真正发生的是这样的:
DoSomething (SomeRange.Value)
不pipe过程签名中隐式的ByRef
修饰符如何 ,括号都告诉VBA 将expression式作为一个值来计算 , 然后 将该expression式 的值 ( ByVal
)传递给被调用的过程。
问题是,给定一个16格的Range
, Range.Value
是一个二维数组,并且给定一个单元格Range
, Range.Value
是一个Variant
,它包含该单元格的值, 并且不可能被强制到一个Range
对象实例 ,所以这里的代码不可能“正常工作”:它是一个对象所需的错误,因为过程期望一个Range
并且给它一个Variant
,它包含一个2D数组。
为什么你的“正常工作”的代码是不是真的工作
testFunc (ThisWorkbook.Sheets("Sheet2").Range("A1:A16"))
唯一的方法可能可行,就是如果testFunc
有这个签名(我怀疑它在最终提出这个问题之前曾经有过一次) :
Function testFunc(aCol)
或者明确的等价物:
Public Function testFunc(ByRef aCol As Variant) As Variant
而且由于二维数组可以迭代For Each
循环( 虽然非常低效 ),并且整个A1:A16
范围可能包含的值可以强制为有效的Integer
数值,但“确实工作正常”……除了你更新数据的内存副本,而不是单元本身 – 所以它不是“很好”,更像是“不崩溃”。
这是一个MCVE:
Private Function DoSomething(ByRef foo As Range) End Function Public Sub Test() DoSomething (Range("A1").Value) End Sub
调用Test
将引发运行时错误424“Object Required”。
Public Function DoSomething(ByRef foo As Range) End Function Public Sub Test() DoSomething (Range("A1:A100").Value) End Sub
调用Test
将引发相同的运行时错误424“Object Required”。
现在删除As Range
声明:
Public Function DoSomething(ByRef foo As Variant) Debug.Print TypeName(foo) End Function Public Sub Test() DoSomething (Range("A1:A100").Value) End Sub
调用Test
Variant()
打印到即时窗格 (Ctrl + G)。 现在让范围只包含一个单元格:
Public Function DoSomething(ByRef foo As Variant) Debug.Print TypeName(foo) End Function Public Sub Test() DoSomething (Range("A1").Value) End Sub
调用Test
打印单元格A1保存的任何数据types。 如果是文本,则打印String
。 如果是数字,则打印Double
。 如果是date,则打印Date
。 如果是单元格错误(例如#VALUE!
#NA
, #VALUE!
等),则会打印Error
。
请注意,上述所有结果是相同的,无论您是否明确指定.Value
,因为忽略.Value
归结为隐式指定它。
还要注意传递一个数组ByVal
是非法的。 这里传递给函数的是指向数组开头的指针的副本 – Variant
数组不是存储数组本身,而是指向其实际位置的指针:这就是为什么以及如何合法地传递variables数组按价值。
为什么这个variables也吹起来了
第二行抛出相同的错误,出于同样的原因:
testFunc (aRange) '<---- error
你隐式地这样做:
testFunc aRange.Value
因为这就是括号所做的:他们告诉VBA 将expression式作为一个值来评估,并将其作为一个值来传递 。
所以你正在传递一个2D变体数组到一个期望Range
。
这是不同的,是正确的:
testFunc aRange
注意缺less圆括号:现在你将Range
对象引用传递给一个接受Range
对象引用ByRef
(尽pipe这个修饰符是隐式的,更正确的方法是通过对象引用ByVal
) 。
那么如何判断参数被评估为一个值呢?
当你调用一个Function
过程时,你通常对它的返回值感兴趣:
result = MsgBox("Confirm?", vbYesNo)
VBA自动在函数的标识符后面定位左括号 – 不留空白。
当您调用一个Function
过程而不捕获它的返回值时,您必须省略括号:
MsgBox "Confirm?", vbYesNo
请注意,这将是一个编译错误:
MsgBox ("Confirm?", vbYesNo)
因为expression式("Confirm?", vbYesNo)
不能被评估为一个值,并传递给过程的第一个参数。
这很容易 – MsgBox
有多个参数。 当只有一个参数时,人们会感到困惑 – 因为这看起来合法:
testFunc (aRange)
注意空白:它不应该在那里 。 这就是VBE告诉你“这些括号不是函数调用的一部分,它们是你要传递给该函数的参数的一部分,如果这些括号中的任何值不能在运行时作为一个值被评估,时间,期待麻烦“ 。
如果你的testFunc
过程没有返回值 ,那么它不应该是一个Function
– 它应该是一个Sub
过程。 函数需要input并返回一个值,Subs 做一些事情 ,通常会带来副作用,例如修改实际的单元格值。
你的代码很可能是这个。
Sub testFunc(aCol As Range) Dim i As Integer i = 0 For Each cell In aCol cell.Value = i i = i + 1 Next End Sub Sub testSub() Dim aRange As Range Set aRange = ThisWorkbook.Sheets("Sheet1").Range("A1:A16") testFunc aRange '<---- error End Sub