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

给定下面的代码:我似乎无法成功地从一个子函数传递一个范围对象variables到另一个。 我花了整整一天的时间进行研究,并在吞噬骄傲之前进行实验并来到这里。

请阅读下面的评论,并回复你有什么想法,为什么最后两行不行为。

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 

从Call关键字语句的msdn文档中 ,

备注

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

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

从实际的angular度来看,尽pipe可以使用或不使用“呼叫”关键字来调用Subs,但是select一种方式并坚持使用它作为编码风格的一部分是有意义的。 我同意共产国际 – 我认为,基于对现代VBA代码的观察,使用“呼叫”关键字应被视为弃用。 相反,在参数列表周围调用没有括号的Subs。

现在对于这个重要问题的答案是:

为什么你的代码抛出一个错误?

以下面的子例程为例:

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

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

ShowSum 45,37

如果它被称为ShowSum(45, 37)会发生什么? 那么,你甚至无法编译,因为VBA立即抱怨“预期=”。 这是因为VBAparsing器看到了括号,并决定这必须是一个Function调用,因此它希望你用一个“=”赋值语句来处理返回值。

那么只有一个参数的Sub呢? 例如:

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

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

 ShowNum (45) 

VBA并不把这些括号视为围绕参数列表 – 而是将它们视为分组括号。 大多数情况下,这并不重要,但是在具有默认成员的对象的情况下。

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

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

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

 +-------------+-----+--------------+ | 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 

好吧,我知道我发布这个问题后,我会被点燃,并得到答案。

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

 **CALL doSomethingToRows(RegionOfInterest)** 

谢谢!

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

 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 

这两个调用完美。 一个与呼叫,另一个没有。

编辑:@Conintern。 谢谢你解释。 我明白现在是什么意思。

不过,我仍然不同意。 如果我宣布如下:

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

并调用它:

Debug.print DisplaySomething(Range(“A1”))

我相信Excel已经很聪明,并转换为一个string。 它可以通过调用默认参数来完成,并可以转换为string。

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

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

没有调用默认参数,但它被调用,因为Excel能够解决它的types。

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

会因为能够强制加倍而返回一倍。

事实上,在这些例子中,默认被调用。 但在这个例子中,我们将其定义为Range。 没有默认调用那里,但它被调用 – 括号或没有括号。

我相信这与Excel和数据强制更有关系。 类似于以下内容:

 Public Function Test(ByVal i As String) As Integer Test = i End Function 

并调用:Debug.printtesting(“1”)

顺便说一句,是的,我知道这不是一个没有默认参数的对象。 我指出数据强制。 Excel尽最大努力来解决它。

可能是错的介意你…