如何将范围obj变量传递给Excel VBA中的子(2016)

时间:2017-02-08 18:49:11

标签: excel vba excel-vba excel-2016

给出以下代码: 我似乎无法成功地将范围对象变量从一个子函数传递到另一个子函数。我花了整整一天时间研究和试验,然后才吞下骄傲来到这里。

请阅读以下评论,并回答您有关为什么最后两行不会表现的任何想法。

Public Sub doSomethingToRows(ROI As Range)
*'do Something with the cell values within the supplied range*

End Sub
'
Public Sub testDoAltRows()

    Dim RegionOfInterest As Range       'is this an object or not?

    '*The following yields: Class doesn't support Automation (Error 430)*
    '*Set RegionOfInterest = New Worksheet 'this just gives an error*

    Set RegionOfInterest = Worksheets("Sheet1").Range("A1")
    RegionOfInterest.Value = 1234.56        '*okay, updates cell A1*

    Set RegionOfInterest = Worksheets("Sheet1").Range("B5:D15")
    RegionOfInterest.Columns(2).Value = "~~~~~~"    '*okay*

    'doSomethingToRows (RegionOfInterest)   'why do I get "OBJECT IS REQUIRED" error?
    doSomethingToRows (Worksheets("Sheet1").Range("B5:C15")) 'but this executes okay
End Sub

3 个答案:

答案 0 :(得分:5)

来自msdn documentation of the Call keyword statement

  

备注

     

调用过程时不需要使用Call关键字。   但是,如果使用Call关键字来调用需要的过程   参数,参数列表必须括在括号中。 如果省略   Call关键字,你也必须省略括号   参数列表即可。如果您使用Call语法来调用任何内在函数或   用户定义的函数,函数的返回值被丢弃。

     

要将整个数组传递给过程,请使用后跟的数组名称   空括号。

从实际的角度来看,即使可以使用或不使用“Call”关键字调用Subs,但选择一种方式并坚持使用它作为编码风格的一部分是有意义的。我同意Comintern的观点 - 基于对现代VBA代码的观察,我认为使用“Call”关键字应该被视为已弃用。相反,在参数列表周围调用不带括号的Subs。

现在回答这个重要问题:

为什么您的代码会出错?

以下面的子程序为例:

Public Sub ShowSum(arg1 As Long, arg2 As Long)
    MsgBox arg1 + arg2
End Sub

我们已经确定,如果不使用Call关键字,必须像这样调用Subs:

ShowSum 45,37

如果它被称为ShowSum(45, 37),会发生什么?好吧,你甚至无法编译,因为VBA立即抱怨“预期=”。这是因为VBA解析器看到括号并确定它必须是 Function 调用,因此它希望您使用“=”赋值语句处理返回值。 / p>

只有一个参数的Sub怎么样?例如:

Public Sub ShowNum(arg1 As Long)
    MsgBox arg1
End Sub

调用此Sub的正确方法是ShowNum 45。但是,如果您在VBA IDE中键入它,该怎么办?ShowNum(45)?一旦将光标移出线条,您就会注意到VBA在子名称和左括号之间添加了一个空格,为您提供关于如何实际解释代码行的关键线索:

ShowNum (45)

VBA并未将这些括号视为包围参数列表 - 而是将它们视为分组括号。大多数情况下,这无关紧要,但在具有默认成员的对象的情况下也是如此。

要查看此问题,请尝试运行以下命令:

Dim v As Variant
Set v = Range("A1")
Set v = (Range("A1"))  '<--- type mismatch here

请注意,标记的行上出现“类型不匹配”。现在将这两个语句添加到监视窗口并查看“类型”列:

+-------------+-----+--------------+
| Expression  |Value|     Type     |
+-------------+-----+--------------+
|Range("A1")  |     |Object/Range  |
|(Range("A1"))|     |Variant/String|
+-------------+-----+--------------+

当您使用分组括号包围对象时,将评估其默认属性 - 对于Range对象,它是Value属性。

因此,VBA允许你在“将参数列表括号括起来”的情况下实际上只是巧合 - 实际上,VBA只是将其解释为分组括号并相应地评估该值。您可以通过在Sub上尝试相同的事情来查看它在VBA中无效以调用参数列表周围带括号的Sub。

@PaulG

试试这个:

Public Sub Main()
    Debug.Print TypeName(Range("A1"))
    Debug.Print TypeName((Range("A1")))
End Sub

答案 1 :(得分:-1)

好吧,我知道在发布这个问题后,我会被灯光击中并得到答案。

将对象VARIABLE传递给子函数并希望使用括号&#34;()&#34;时,必须使用CALL!因此,对我的代码示例的更正是:

**CALL doSomethingToRows(RegionOfInterest)**

谢谢!

答案 2 :(得分:-3)

也许我们正在谈论不同的事情,但这里有一个例子让我的意思更清楚一点。

BoostTimer

两个电话都完美无缺。一个用Call而另一个没有。

编辑: @Conintern。谢谢你的解释。我明白现在的意思了。

然而,我仍然不同意。 如果我宣布以下内容:

startTimer

并调用它:

Debug.print DisplaySomething(范围(&#34; A1&#34;))

我相信Excel一直很聪明并且转换为字符串。它可以通过调用默认参数来实现,并可以转换为字符串。

但是,与原始参数示例中一样,如果我声明以下内容:

Option Explicit

Sub TestDisplay()
Dim r As Range

'Create some range object
Set r = Range("A1")
'Invoke with Call.
Call DisplaySomething(r)
'Invoke without Call.
DisplaySomething r

End Sub

Sub DisplaySomething(ByVal Data As Range)
Debug.Print "Hi my type is " & TypeName(Data)
End Sub

默认参数没有调用,但是调用它,因为Excel能够将其解析为该类型。

Function DisplaySomething(ByVal Data As String)
DisplaySomething = "Hi my type is " & TypeName(Data)
End Function

将返回一个double,因为它能够强制转换为double。

确实在这些例子中调用了Default。 但是在这个例子中我们定义为Range。 No Default在那里调用但是它被调用 - 括号或没有括号。

我认为这更多地与Excel和数据强制有关。 类似于以下内容:

Function DisplaySomething(ByVal Data As Range)
DisplaySomething = "Hi my type is " & TypeName(Data)
End Function

并调用: Debug.print测试(&#34; 1&#34;)

顺便说一句,是的,我知道这不是一个没有默认参数的物体。我指出数据强制。 Excel会尽力解决它。

你可能错了......