Vba 如何处理在运行时返回值类型未知的函数(对象或非对象)

Vba 如何处理在运行时返回值类型未知的函数(对象或非对象),vba,Vba,这个问题围绕调用CallByName的返回值展开。我有一个名为PropertyPtr的类,该类用作指向对象属性的通用指针。它包含对对象的引用及其一个属性的名称。它公开了一个Getter和Setter方法 地产展品: 在Getter中,我的CallByName可以返回一个对象,也可以不返回。但是我能看到的测试CallByName值是否为对象的唯一方法是运行它两次——一次是在IsObject内部进行测试,然后再次获取对该值的引用。我能看到的唯一其他方法是捕捉错误。然后,您至少有时只运行CallByN

这个问题围绕调用CallByName的返回值展开。我有一个名为PropertyPtr的类,该类用作指向对象属性的通用指针。它包含对对象的引用及其一个属性的名称。它公开了一个Getter和Setter方法

地产展品:

在Getter中,我的CallByName可以返回一个对象,也可以不返回。但是我能看到的测试CallByName值是否为对象的唯一方法是运行它两次——一次是在IsObject内部进行测试,然后再次获取对该值的引用。我能看到的唯一其他方法是捕捉错误。然后,您至少有时只运行CallByName两次


我的问题是:是否有其他方法可以在不运行CallByName两次的情况下执行此操作?

好的,因此如果您真的想遵循此路线,那么我认为您必须设置IsObj标志-可能是在设置属性名的时候

但是,我仍然认为,对对象或基元类型使用变量不是一个好主意,在这种情况下,CallByName函数会带来一些问题。我犹豫不决的是,性能会降低,如果将来要更新内容,您将有相当多的任务来保持属性字符串与属性名称对齐

可以在VBA中实现中介模式,我觉得你应该考虑这条路线。下面是一个非常基本的例子,说明了如何做到这一点。我没有为中介人创建接口,但我已经为我的参与类创建了一个接口,以涵盖您处理自己的类“组”的可能性

名为cMediator的中介类:

参与类接口称为ISweet:

我的两个参与课程cQtySweet和cWeightSweet:

模块代码:

…输出如下所示:

新的政府限制

最大停止次数:40

Max Wine Gums:100

马克斯·谢伯特:250克

最大软糖:400克

甜蜜的警报

软糖正在融化。现在就吃葡萄酒口香糖吧

软糖正在融化。现在就吃软糖


你能解释一下这门课的目的吗。我的感觉是,您的体系结构不太正确——即使您在Getter中解决了对象检查问题,您是否需要在调用该类属性的例程中重复检查?拥有可以保存对象或基本数据类型的变体通常是设计不正确的标志。我不是说你的是,但是理解这门课的目的会很有趣。@Ambie-你的观点很有道理。我必须应用相同的对象来检查堆栈。这里最好的选择可能是包含IsObject属性标志。此类的目的是允许跨对象的不同类型和实例(如中介模式)执行批处理。你可以有一个类似于PropertyPtr的集合,当需要调解时,它可以在属性列表中运行,并跨类型/实例更新/使用/etc它们。我有另一个类似的FunctionPtr类,它模拟将函数存储在Javascript之类的变量中感谢你发布了这个详细的示例!我发现它非常有用,因为我了解了更多关于设计模式的知识,以及如何在VBA中实现它们。。。有时是一项令人沮丧的任务。我认为关于变量类型的CallByName,您是对的。这将迫使所有想要参与的对象声明变量类型属性。
Option Explicit

Public Obj As Object
Public PropertyName As String

Public Sub Setter(Val As Variant)
    If IsObject(Val) Then
        CallByName Me.Obj, Me.PropertyName, VbSet, Val
    Else
        CallByName Me.Obj, Me.PropertyName, VbLet, Val
    End If
End Sub

Public Function Getter() As Variant
    If IsObject(CallByName(Me.Obj, Me.PropertyName, VbGet)) Then
        Set Getter = CallByName(Me.Obj, Me.PropertyName, VbGet)
    Else
        Getter = CallByName(Me.Obj, Me.PropertyName, VbGet)
    End If
End Function
Option Explicit

Private mSweets As Collection

Private Sub Class_Initialize()
    Set mSweets = New Collection
End Sub

Public Sub RegisterSweet(sweet As ISweet)
    Set sweet.Mediator = Me
    mSweets.Add sweet
End Sub

Public Sub SendSugarLimit(limit As Long)
    Dim sweet As ISweet

    For Each sweet In mSweets
        sweet.ReceiveSugarLimit limit
    Next
End Sub

Public Sub ReceiveMeltingAlert(offender As String)
    Dim sweet As ISweet

    For Each sweet In mSweets
        sweet.ReceiveEatNow offender
    Next
End Sub
Option Explicit

Public Property Set Mediator(RHS As cMediator)
End Property

Public Sub ReceiveSugarLimit(g_perDay As Long)
End Sub

Public Sub ReceiveEatNow(offender As String)
End Sub
Option Explicit
Implements ISweet

Public Name As String
Public SugarPerItem As Long
Public CanMelt As Boolean
Private pMediator As cMediator

Public Sub OhNoItsMelting()
    pMediator.ReceiveMeltingAlert Name
End Sub

Private Property Set ISweet_Mediator(RHS As cMediator)
    Set pMediator = RHS
End Property

Private Sub ISweet_ReceiveEatNow(offender As String)
    If CanMelt Then Debug.Print offender & " is melting. Eat " & Name & "s now!"
End Sub

Private Sub ISweet_ReceiveSugarLimit(g_perDay As Long)
    Dim max As Long

    max = g_perDay / SugarPerItem
    Debug.Print "Max " & Name & "s: " & max & "."
End Sub

Option Explicit
Implements ISweet

Public Name As String
Public SugarPer100g As Long
Public CanMelt As Boolean
Private pMediator As cMediator

Public Sub OhNoItsMelting()
    pMediator.ReceiveMeltingAlert Name
End Sub
Private Property Set ISweet_Mediator(RHS As cMediator)
    Set pMediator = RHS
End Property

Private Sub ISweet_ReceiveEatNow(offender As String)
    If CanMelt Then Debug.Print offender & " is melting. Eat " & Name & " now!"
End Sub

Private Sub ISweet_ReceiveSugarLimit(g_perDay As Long)
    Dim max As Long

    max = g_perDay / (SugarPer100g / 100)
    Debug.Print "Max " & Name & ": " & max & "g."
End Sub
Public Sub RunMe()
    Dim m As cMediator
    Dim qtySweet As cQtySweet
    Dim weightSweet As cWeightSweet

    Set m = New cMediator

    Set qtySweet = New cQtySweet
    With qtySweet
        .Name = "Gobstopper"
        .SugarPerItem = 5
        .CanMelt = False
    End With
    m.RegisterSweet qtySweet

    Set qtySweet = New cQtySweet
    With qtySweet
        .Name = "Wine Gum"
        .SugarPerItem = 2
        .CanMelt = True
    End With
    m.RegisterSweet qtySweet

    Set weightSweet = New cWeightSweet
    With weightSweet
        .Name = "Sherbert"
        .SugarPer100g = 80
        .CanMelt = False
    End With
    m.RegisterSweet weightSweet

    Set weightSweet = New cWeightSweet
    With weightSweet
        .Name = "Fudge"
        .SugarPer100g = 50
        .CanMelt = True
    End With
    m.RegisterSweet weightSweet

    'Blasted government has reduced sugar allowance.
    Debug.Print "New govt. limits..."
    m.SendSugarLimit 200

    'Phew what a scorcher - the fudge is melting in my pocket.
    Debug.Print "Sweet alarm..."
    weightSweet.OhNoItsMelting
End Sub