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格的RangeRange.Value是一个二维数组,并且给定一个单元格RangeRange.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