VBA:如何使用值初始化对象?

26

我想要能够初始化一个具有以下属性的 CArticle:

Private pNumber As String
Private pQuantity As Double

如何使用空值、预定义值或当前值创建一个新的CArticle?我在想以下代码:

New empty CArticle

pNumber
pQuantity

新的虚拟CArticle

pNumber
pQuantity = 99999

新的初始化方法CArticle(number, quantity)

pNumber = number
pQuantity = quantity

是的,它完全是 https://dev59.com/YWUp5IYBdhLWcg3whn1z#15224115 的副本。 - ElderDelp
Matt的回答是在这些情况下前进的方式,请查看他的答案 - Ricardo Diaz
3个回答

35

这真是让人头疼,但这是唯一的方法。

文件 CArticle

Option Explicit

Private pNumber As String
Private pQuantity As Double

Private Sub Class_Initialize()
    pNumber = vbNullString
    pQuantity = 0
End Sub

Public Sub InitializeWithValues(ByVal number As String, ByVal quantity As Double)
    pNumber = number
    pQuantity = quantity
End Sub

Public Sub InitializeDefaultValues()
    pNumber = vbNullString
    pQuantity = 99999
End Sub

在调用模块中

Dim art As New CArticle       ' Initialize value to empty
art.InitializeWithValues "Bowtie", 100     ' and assign values

Set art = New CArticle        ' Initialize values to empty
art.InitializeDefaultValues   ' Initialize values to default

3
创建一个 InitializeFromRange(ByVal r as Range) 方法可以从工作表中的表格中提取数值,这可能会很有用。 - John Alexiou

2
如果有人像我一样通过搜索到达这里,我建议查看StackOverFlow: 在VBA中传递参数给构造函数中的答案。 这不是我的答案,它来自Bgusach。我在这里包含它,因为我认为一个有用的答案不仅仅是一个链接。

在VBA中传递参数给构造函数

这是我最近使用的一个小技巧,效果很好。Bgusach想与那些经常与VBA打交道的人分享。

1.- 在每个自定义类中实现一个公共初始化子程序。我在所有类中都称其为InitiateProperties。此方法必须接受您想要发送到构造函数的参数。

创建一个名为“factory”的模块,并创建一个公共函数,函数名称为类的名称加上单词“Create”,输入参数与构造函数相同。此函数必须实例化您的类,并调用初始化子程序(第1点中解释),传递接收到的参数。最后返回已实例化和初始化的方法。
例如:
假设我们有自定义类Employee。与前面的示例一样,它必须使用名称和年龄进行实例化。
这是InitiateProperties方法。 m_name和m_age是要设置的私有属性。
Public Sub InitiateProperties(name as String, age as Integer)

    m_name = name
    m_age = age

End Sub

现在在工厂模块中:
Public Function CreateEmployee(name as String, age as Integer) as Employee

    Dim employee_obj As Employee
    Set employee_obj = new Employee

    employee_obj.InitiateProperties name:=name, age:=age
    set CreateEmployee = employee_obj

End Function

最后,当您想要实例化一个员工时。
Dim this_employee as Employee
Set this_employee = factory.CreateEmployee(name:="Johnny", age:=89)

特别适用于您有多个类的情况。只需在模块工厂中为每个类放置一个函数,并通过调用 factory.CreateClassA(arguments)factory.CreateClassB(other_arguments) 等来实例化。

编辑

正如 stenci 指出的那样,您可以通过避免在构造函数中创建本地变量来使用更简洁的语法完成相同的操作。例如,CreateEmployee 函数可以这样编写:

Public Function CreateEmployee(name as String, age as Integer) as Employee

    Set CreateEmployee = new Employee
    CreateEmployee.InitiateProperties name:=name, age:=age

End Function

这句话的意思是:“哪一个更好。”

0
我知道这是一个老问题,但至少我可以在运行时强制使用工厂函数。
基本上,你不能将参数传递给类的初始化器,所以像下面的代码 somevar = New SomeUserClass("Some Initializer") 是无法工作的。使用一个公共的创建函数是一个不错的选择,可以将初始化参数引入其中,但它仍然允许使用 somevar = New SomeUserClass 而没有任何惩罚。在这种情况下,你可以设置一个已初始化的标志,并在每个函数中进行检查,但这也很繁琐。
我提出的解决方案是,如果使用 New SomeUserClass 而不是工厂函数,则抛出运行时错误。这样,在允许执行其代码之前,你的公开成员函数可以操作已完全初始化的对象。
' Factory.bas

Option Explicit

Private m_globalInitializer As Variant

' This could also just be a function
Public Property Get GlobalInitializer() As Variant
    If IsEmpty(m_globalInitializer) Then _
        Err.Raise 5, , "The factory function must be used to create an instance of this class"
        ' Error #5 is 'Invalid procedure call or argument'

    ' Coerce any type of value to be returned
    If IsObject(m_globalInitializer) Then
        Set GlobalInitializer = m_globalInitializer
    Else
        GlobalInitializer = m_globalInitializer
    End If

    ' Make this getter a one-time use
    m_globalInitializer = vbEmpty
End Property

Public Function CreateSomeUserClass(ByVal somearg1 As String, _
    ByVal somearg2 As Object) As SomeUserClass

    ' You can set m_globalInitializer to anything your class initializer expects
    m_globalInitializer = Array(somearg1, somearg2)

    ' This is the only place this is allowed
    Set CreateSomeUserClass = New SomeUserClass 
End Function

' SomeUserClass.cls

Option Explicit

Private m_somevar1 As String
Private m_somevar2 As Object

Private Sub Class_Initialize()
    Dim args() As Variant
    args = GlobalInitializer ' This clears the global initializer as well
        ' allowing other objects to be factory created

    m_somevar1 = args(0)
    Set m_somevar2 = args(1)

    ' Continue rest of initialization, including calling other factories
    ' that use the GlobalInitializer idiom.
End Sub

如果在工厂函数之外调用New方法,将会导致运行时错误。没有任何方式可以在使用New方法之前设置私有变量m_globalInitializer,因此你的初始化参数是被强制执行的。
希望这能帮到你!

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