VBA 中的类(静态)方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/396117/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 09:32:38  来源:igfitidea点击:

Class (Static) Methods in VBA

vbastatic

提问by Tom

I wonder, whether it is possible to create class-methods in VBA. By class-method I mean methods that can be called without having an object of the class. The 'static'-keyword does that trick in C++ and Java.

我想知道,是否可以在 VBA 中创建类方法。通过类方法,我的意思是可以在没有类对象的情况下调用的方法。'static' 关键字在 C++ 和 Java 中起到了这个作用。

In the example below, I try to create a static factory method.

在下面的示例中,我尝试创建一个静态工厂方法。

Example:

例子:

'Classmodule Person'
Option Explicit
Private m_name As String
Public Property Let name(name As String)
    m_name = name
End Property
Public Function sayHello() As String
    Debug.Print "Hi, I am " & m_name & "!"
End Function

'---How to make the following method static?---'
Public Function Create(name As String) As Person
    Dim p As New Person
    p.m_name = name
    Set Create = p
End Function

'Using Person'
Dim p As New Person
p.name = "Bob"
p.sayHello 'Works as expected'
Set p2 = Person.Create("Bob") 'Yields an error'

采纳答案by Tom

That ("Public Shared") would only work in VB.Net.

那(“公共共享”)只能在 VB.Net 中工作。

There is no way to define Class Methods in VBA (or VB). I'd suggest to create a public function in a module.

无法在 VBA(或 VB)中定义类方法。我建议在模块中创建一个公共函数。

回答by Matthew Paul Arnold

1.Create a normal class containing the public method(s) you need to be 'static'

1.创建一个包含公共方法的普通类,您需要“静态”

2.Include a public method [in this 'static' class] that initialises the [private] 'static fields' within the class (it can take parameters if you wish)

2.包括一个公共方法[在这个'静态'类中],它初始化类中的[私有]'静态字段'(如果你愿意,它可以带参数)

3.Create a module acts as a factory

3.创建一个模块作为工厂

Public Function CreateStaticClass(parameters for 'constructor') As StaticClass

    Dim static As StaticClass
    Set static = New StaticClass
    Call StaticClass.Constructor(pass in parameters)
    Set CreateStaticClass = static

End Function

4.you can now use the 'static' class by calling CreateStaticClass('parameters').MethodName('parameters') there is no need to initialise the instance as that is done by the factory method

4.您现在可以通过调用 CreateStaticClass('parameters').MethodName('parameters') 来使用“静态”类,无需像工厂方法那样初始化实例

5. (Optional)If you want to enforce singleton instances you can create a module that acts as a singleton container - include a private instance variable and a public accessor property. optionally you can use a 'let' setter to allow the singleton to be 'replaced' with a new [static] class (using different constructor parameters - see #2,3). Use 'Let' for the setter, so you can assign the singleton without using 'set' ala OO languages

5.(可选)如果您想强制执行单例实例,您可以创建一个充当单例容器的模块 - 包括一个私有实例变量和一个公共访问器属性。可选地,您可以使用“let”设置器来允许用新的 [静态] 类“替换”单例(使用不同的构造函数参数 - 参见 #2,3)。对 setter 使用 'Let',这样您就可以在不使用 'set' ala OO 语言的情况下分配单例

Private curStaticClass as StaticClass

Public Property Get CurrentStaticClass() As StaticClass 

    If curStaticClass Is Nothing Then Set curStaticClass = CreateStaticClass

    Set CurrentStaticClass = curStaticClass  

End Property

Public Property Let CurrentStaticClass(value As StaticClass)

    If Not (curStaticClass Is Nothing) Then Set curStaticClass = Nothing

    Set curStaticClass = value 

End Property

6.To assign the singleton:

6.分配单例:

CurrentStaticClass = CreateStaticClass(parameters)

7.To use the singleton:

7.使用单例:

[value = ] CurrentStaticClass.MethodName(parameters)

回答by i_saw_drones

You could try setting the VB_PredeclaredIdattribute of the class you wish to be static to True. This creates a default instance of the class in much the same way that forms work in VBA (notice that you can refer to them directly without creating an instance. I know that this is not best practice but it is possible).

您可以尝试将VB_PredeclaredId您希望静态的类的属性设置为True. 这将创建类的默认实例,其方式与 VBA 中的表单工作方式大致相同(请注意,您可以直接引用它们而无需创建实例。我知道这不是最佳实践,但它是可能的)。

This means that you would have more of a singleton-style class, but it could serve your requirements...

这意味着您将拥有更多的单例样式类,但它可以满足您的要求......

You can't set this directly from the VBA IDE itself, however, you can perform the following steps:

您不能直接从 VBA IDE 本身进行设置,但是,您可以执行以下步骤:

1.Export the class you wish to make static to a folder.

1.将您想要静态化的类导出到一个文件夹中。

2.Open the .clsfile you exported in your favourite text editor and change the entry for VB_PredeclaredIdso that it reads VB_PredeclaredId = True.

2..cls在您喜欢的文本编辑器中打开您导出的文件并更改其条目VB_PredeclaredId,使其显示为VB_PredeclaredId = True

3.Save the file and re-import into VBA.

3.保存文件并重新导入到 VBA。

You should then be able to call your public methods on the class without having to instantiate the class. Bear in mind that the Initializemethod is only called the first time you execute a class method/access a class property, and Terminatemethod is never called. Therefore you may wish to write your own constructor and also ensure you explicitly call the destructor if you need one.

然后,您应该能够在类上调用公共方法,而无需实例化该类。请记住,该Initialize方法仅在您第一次执行类方法/访问类属性时才被调用,并且Terminate永远不会调用该方法。因此,您可能希望编写自己的构造函数,并确保在需要时显式调用析构函数。

Reference: UtterAccess.com Singleton Example

参考:UtterAccess.com 单例示例

Reference: http://msdn.microsoft.com/en-us/library/ee199159.aspx

参考:http: //msdn.microsoft.com/en-us/library/ee199159.aspx

回答by Swanny

Bit late in the day but what the heck

一天有点晚,但到底是什么

There are no class or static methods in VB6/VBA. But you can explicity state the name of a module. You can't have a module and a class of the same name but you could call it something similar.

VB6/VBA 中没有类或静态方法。但是您可以明确说明模块的名称。你不能有一个模块和一个同名的类,但你可以称之为类似的东西。

So I could have a class called Employee and a module called EmployeeUtil and then I can write:

所以我可以有一个名为 Employee 的类和一个名为 EmployeeUtil 的模块,然后我可以写:

  Dim emp As Employee
  Dim code As String
  Set emp = EmployeeUtil.Create( "Smith", "John", 21-Feb-1988)
  code = "123XY"
  If EmployeeUtil.IsCodeValid( code) Then
    emp.Code = code
  Else
    emp.Code = EmployeeUtil.DefaultCode
  EndIf

Yes, the values are hard coded and the code handling should probably be under the property setter but that is not the point I'm trying to make. EmployeeUtil is essentially being a place holder for non-instance members.

是的,这些值是硬编码的,代码处理可能应该在属性设置器下,但这不是我想要表达的重点。EmployeeUtil 本质上是非实例成员的占位符。

You'll note that the Create method this way gives us a pseudo like constructor for the Employee class. All that function does is create an instance of Employee, assign the parameters via the property setters and then returns the instance. If your constructing instances of objects in a lot of places, then this can save a lot of code.

您会注意到 Create 方法以这种方式为我们提供了一个类似于 Employee 类的伪构造函数。该函数所做的就是创建一个 Employee 实例,通过属性设置器分配参数,然后返回该实例。如果你在很多地方构造对象的实例,那么这样可以节省大量的代码。

回答by Mike Woodhouse

AFAIK, the closest you can get (and it's not that close) is to use an "anonymous" instance, so something like this:

AFAIK,你能得到的最接近的(而且不是那么接近)是使用“匿名”实例,所以是这样的:

With New NotReallyStaticClass
    .PerformNotReallyStatic Method, OnSome, Values
End With

回答by xxbbcc

While this is not strictly an answer to the question itself, I'd like to point out that Mike Woodhouse's solution should be avoided. Every time creating a new instance of an object is a performance hit and it really doesn't solve the original problem - it doesn't create a static object and it doesn't provide static methods either.

虽然这并不是对问题本身的严格回答,但我想指出应该避免使用 Mike Woodhouse 的解决方案。每次创建对象的新实例都会影响性能,而且它确实没有解决原始问题——它不创建静态对象,也不提供静态方法。

Since VBA has no concept of class functions, the closest one can get is using functions in modules.

由于 VBA 没有类函数的概念,因此最接近的是在模块中使用函数。

As for factory methods, I suggest creating a module with the word Factory appended to the name of the class the module is creating. Something like:

至于工厂方法,我建议创建一个模块,在该模块正在创建的类的名称后附加 Factory 一词。就像是:

'Module PersonFactory
Option Explicit

Public Function Create(ByVal sName As String) As Person

    'Code here

End Function

This is far from the static method concept of other languages but at least it provides a pattern that can be used in a project.

这与其他语言的静态方法概念相去甚远,但至少它提供了一种可以在项目中使用的模式。

回答by fuat aygan

Instancing property of a similar class is available for use in static classes. Instancing property for it 'GlobalMultUse' must specify.

类似类的实例化属性可用于静态类。它的实例化属性 'GlobalMultUse' 必须指定。

Static class example:

静态类示例:

' Error Class in ClassInstancing ActiveDLL project
Option Explicit

Private m_errorID As Integer
Private m_Description As String

Public Property Get ErrorID() As Integer
ErrorID = m_errorID
End Property

Public Property Let ErrorID(ByVal vNewValue As Integer)
m_errorID = vNewValue
End Property

Public Property Get Description() As string
    Description = m_Description
End Property

Public Property Let Description(ByVal vNewValue As string)
    m_Description = vNewValue
End Property

Public Function Error() As Error
    Dim errorInstance As New ClassInstancing.Error

    With errorInstance
        .ErrorID = Me.ErrorID
        .Description = Me.Description
    End With

    Set Error = errorInstance
End Function

Public Sub RaiseError(ByVal pErrorID As Integer, ByVal errorSource As String, ByVal errorDesc As String)
Err.Raise pErrorID, errorSource, errorDesc
End Sub

Public Sub ShowError()
   MsgBox "Error ID: " & CStr(Me.ErrorID) & vbCrLf & _
    "Desc: " & Me.Description
End Sub

GlobalMultiUse Instancing property to specify the class as a set of...

GlobalMultiUse Instancing 属性将类指定为一组...

Sample usage this global (static!) class in other standart EXE project:

在其他标准 EXE 项目中使用此全局(静态!)类的示例:

Private Sub Command1_Click()

    ClassInstancing.Description = "Sample-1 error using !"
    ClassInstancing.ErrorID = 9990

    'Dim multiuseClass As ClassInstancing.Error
    'Set multiuseClass = ClassInstancing.Error

    MsgBox ClassInstancing.Error.ErrorID & vbCrLf & ClassInstancing.Error.Description, vbInformation, "Sample Usage 1"

    ClassInstancing.Description = "Sample-2 error using !"
    ClassInstancing.ErrorID = 1110

    ClassInstancing.ShowError
End Sub

Finally, notes in MSDN ((MSDN Library Visual Studio 6.0, 'Instancing Property')):

最后,MSDN 中的注释((MSDN Library Visual Studio 6.0,'Instancing Property')):

GlobalMultiUse. Similar to MultiUse, with one addition: properties and methods of the class can be invoked as if they were simply global functions. It's not necessary to explicitly create an instance of the class first, because one will automatically be created.

全球多用途。与 MultiUse 类似,但有一个补充:可以像调用全局函数一样调用类的属性和方法。没有必要先显式创建类的实例,因为会自动创建一个实例。

回答by fuat aygan

you have to declare p2 before you can use the Set as follows:

您必须先声明 p2 才能使用 Set ,如下所示:

dim p2 as Person

将 p2 调暗为人

Once you do this, you have to replace the Set statement using a standard assignment: p2 = Person.Create("Bob")

执行此操作后,您必须使用标准赋值替换 Set 语句: p2 = Person.Create("Bob")

In the Function: remove the "Set" key word...this could also be the source of an error.

在函数中:删除“设置”关键字...这也可能是错误的来源。

I'm flying blind, but logically it seems like this should work. I am new to using Class modules in VBA but they aren't too different from using VB.Net properties.

我盲目飞行,但从逻辑上讲,这似乎应该有效。我是在 VBA 中使用 Class 模块的新手,但它们与使用 VB.Net 属性并没有太大区别。