在Excel VBA中将函数或子程序存储在数组中

7
在C/C++中,当我有一堆函数(指针)时,可以将它们存储在数组或向量中,并以某种顺序调用其中的一些。在VBA中是否也可以做类似的事情呢?
谢谢!

我认为在 VBA 中这是不可能的。如果您尝试这样做,将会出现编译错误。 - Amen Jlili
1
@JLILIAman 绝对可以实现,只是不是 OP 习惯的方式。 - RubberDuck
嗯,“这要看情况”。在VBA中的问题不在于存储指针,而是首先获取它们,然后稍后使用它们。但是,根据上下文,有各种各样的模糊方法可以做到这一点。那么...你想做什么,为什么要这样做? - RBarryYoung
@RubberDuck 给我展示一个例子。 - Amen Jlili
1
@JLILIAman,请查看我下面的答案。我在这种问题上有一些经验。 - RubberDuck
2个回答

15
是的,但我不建议这样做。VBA实际上并不适合这种操作。由于您标记了Excel问题,因此我将介绍如何在该Office产品中执行此操作。通用概念适用于大部分Office套件,但每个不同的产品对于Application.Run方法都有不同的语法。
首先,重要的是要了解动态调用子程序(sub/function)的两种不同方法以及何时使用每种方法。

Application.Run

Application.Run将运行储存在标准*.bas模块中的子过程或调用函数。
第一个参数是过程的名称(作为字符串传递)。之后,您可以传递多达30个参数。(如果您的过程需要更多参数,请修改代码。)
还有两件关于Application.Run需要注意的事情:
  1. 不能使用命名参数。参数必须按位置传递。
  2. 作为参数传递的对象会被转换为值。这意味着,如果您尝试运行需要具有默认属性对象的过程作为参数,则可能会遇到意外问题。
Public Sub Test1()
    Application.Run "VBAProject.Module1.SomeFunction"
End Sub

要点:

在使用标准模块时,请使用Application.Run。

VBA.Interaction.CallByName

CallByName可执行对象的方法,或设置/获取对象的属性。

它将你要调用该方法的对象实例作为参数,以及方法名称(同样作为字符串)。

Public Sub Test2()
    Dim anObj As SomeObject
    Dim result As Boolean

    result = CallByName(anObj, "IsValid")
End Sub

要点:

CallByName 用于调用类的方法。

没有指针。

正如你所看到的,这些方法都没有使用实际指针(至少不是外部指针)。它们接收字符串,然后使用这些字符串找到要执行的过程的指针。因此,您需要知道要执行的过程的确切名称。您还需要知道需要使用哪种方法。 CallByName 需要一个要调用的对象的实例作为额外的负担。无论哪种方式,您都可以将这些名称作为字符串存储在数组或集合内。(甚至可以考虑使用字典)

因此,您可以将这些硬编码为字符串,也可以尝试在运行时提取适当的过程名称。为了提取过程名称,您需要通过Microsoft Visual Basic for Applications Extensibility库与VBIDE本身进行交互。在此处解释所有内容需要太多的代码和工作量,但我可以指向一些好的资源。

文章和SE问题:

  1. Chip Pearson's Programming The VBA Editor
  2. Extending the VBA Extensibility Library
  3. Ugly workaround to get the vbext_ProcKind is breaking encapsulation
  4. Automagic testing framework for VBA
  5. How to get the procedure or function name at runtime
  6. Import Lines of Code
  7. Meta Programming in VBA: The VBIDE and Why Documentation is Important

来自我的问题和答案的代码:

  1. vbeCodeModule
  2. vbeProcedure
  3. vbeProcedures

3
好的回答,正是我在上面评论中所提到的,但我太忙/懒得详细阐述了。 - RBarryYoung
谢谢@RBarryYoung。显然我对这种特定类型的问题有经验。= ;)- - RubberDuck

1
一个解决方法是使用枚举并使用switch语句。您可以将枚举类型(longs)存储在数组中。例如:
Enum FType
    func1
    func2
    func3
End Enum

Sub CallEnumFunc(f As FType, arg As String)
    Select Case f
        Case func1: MyFunction1(arg)
        Case func2: MyFunction2(arg)
        Case func3: MyFunction3(arg)
    End Select
End Sub

Dim fArray(1) As FType
fArray(0) = func1
fArray(1) = func2
CallEnumFunc fArray(1), "blah"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接