VBA对象实例如何判断它是否为默认实例?

VBA对象实例如何判断它是否为默认实例?,vba,Vba,这不起作用: i、 eclsTestDefaultInstance.CallMe()outputshowamiInitialized=99,因为即使对于默认实例也会调用Class\u Initialize() VERSION 1.0 CLASS BEGIN MultiUse = -1 'True END Attribute VB_Name = "clsTestDefaultInstance" Attribute VB_GlobalNameSpace = False Attribute

这不起作用:



i、 e
clsTestDefaultInstance.CallMe()
outputs
howamiInitialized=99
,因为即使对于默认实例也会调用
Class\u Initialize()

VERSION 1.0 CLASS
BEGIN
  MultiUse = -1  'True
END
Attribute VB_Name = "clsTestDefaultInstance"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
Option Compare Database
Option Explicit

' test how class instance can tell if it is default
'clsTestDefaultInstance

Dim HowAmIInitialised As Integer

Private Sub Class_Initialize()
  HowAmIInitialised = HowAmIInitialised + 1
End Sub

Public Sub CallMe()
  Debug.Print "HowAmIInitialised=" & HowAmIInitialised
End Sub

这真的很简单。。。只需将实例的对象指针与默认实例的对象指针进行比较:

'TestClass.cls (VB_PredeclaredId = True)
Option Explicit

Public Property Get IsDefaultInstance() As Boolean
    IsDefaultInstance = ObjPtr(TestClass) = ObjPtr(Me)
End Property
测试代码表明它工作正常:

Private Sub TestDefaultInstance()
    Dim foo(9) As TestClass

    Dim idx As Long
    For idx = LBound(foo) To UBound(foo)
        If idx = 5 Then
            Set foo(idx) = TestClass
        Else
            Set foo(idx) = New TestClass
        End If
    Next

    For idx = LBound(foo) To UBound(foo)
        Debug.Print idx & foo(idx).IsDefaultInstance
    Next
End Sub
话虽如此,请注意,这有几个注意事项:

  • 如果您检查是否有任何实例是默认实例,它几乎可以保证默认实例将被重新实例化,因为您可能知道,只要引用默认实例,如果它还没有实例化,它就会被重新实例化
  • 如果您
    卸载它(对于
    用户表单
    ),或者将其设置为
    ,然后使其再次自动实例化,则默认实例可以更改。最好将
    VB\u PredeclaredId
    想象成一种契约,如果直接使用类名,您将始终获得一个实例。该合同不能保证它总是相同的。将以下代码添加到上述
    TestDefaultInstance
    过程的底部将演示:

    'This doesn't effect anything that stored a reference to it.
    Set TestClass = Nothing
    'Make a call on the default to force it to reinstantiate.
    Debug.Print TestClass.IsDefaultInstance
    'This will now be false.
    Debug.Print foo(5).IsDefaultInstance
    

您可以使用Class_Initialize和类中的静态函数来存储默认实例,从而获得默认实例

使用我的类clsCustomer的示例摘录,该类的VB_PredeclaredId=True

'注意类_Initialize在第一次访问clsCustomer时被调用 '您还可以做一些事情,如If Not Me Is clsCustomer for singleton类,即不能创建除默认实例之外的实例

私有子类_Initialize()

端接头

静态函数GetDefaultInstance()作为clsCustomer

Dim pvtDefaultInstance As clsCustomer
If pvtDefaultInstance Is Nothing Then
    If Not Me Is Nothing Then
       Set pvtDefaultInstance = Me
   End If
End If
Set GetDefaultInstance = pvtDefaultInstance
端函数 在要测试的模块中

子TestDefaultInstance()

端接头

公共函数是布尔形式的默认值(byval defaultObject作为对象,byval compareObject作为对象)

Dim isDefault as Boolean
if defaultObject is compareObject then
  isDefault = True
End if
IsDefaultInstance = isDefault 
端函数

输出

2401988144720(默认实例)

0(pvtCustomer实例尚未设置且等于零)

2401988144720(默认实例)

2401988142160(与默认实例不同的新pvtCustomer实例)

False(返回False,因为客户默认对象实例与新的pvtCustomer对象不同)


注意:每次运行时,输出ObjPtr都会有所不同,即它们是内存引用,仅用于示例

@GSerg:恐怕这是不对的。设置
VB\u PredeclaredId=True
,然后可以创建用户定义类的全局默认实例。问题是:为什么OP需要找出他是否在使用自己类的默认实例。我觉得这很奇怪。要么你在写代码的时候就知道了,要么……该死的新手,难道他们不能正确地提问吗!在编辑的问题中列出了完整的类…那么,我是否正确地告诉您,您希望在类中知道它是由全局默认实例调用的,还是由您声明的变量调用的,对吗。我不知道这是否可能,对不起。但不管怎样,你为什么要知道这些?您编写代码,就知道它是否是默认实例。也许你在寻找类似于或的东西。@GSerg这个问题是有效的,即使它目前没有任何理由:我在寻找全局默认实例和显式创建实例之间的内在动态区别。我突然想到,
Class\u Initialize()
可能不会为全局默认值调用,但我的测试表明它是(就像在该例程上放置断点一样)这是一个合理的动机:将全局实例用作单例。如果发现任何显式创建的实例,程序将失败。谢谢,向上投票。当然,你只需要比较“地址”。有时你看不见树木,也看不见森林:——)@Storax你只需要寻找树木@Storax和Comintern:说到抽象级别,更“高级”的代码可能是
IsDefaultInstance=Me是TestClass
;当然,在类模块内部
If Me Is clsCustomer Then
    GetDefaultInstance
End If
Dim pvtDefaultInstance As clsCustomer
If pvtDefaultInstance Is Nothing Then
    If Not Me Is Nothing Then
       Set pvtDefaultInstance = Me
   End If
End If
Set GetDefaultInstance = pvtDefaultInstance
Dim pvtCustomer As clsCustomer
Debug.Print ObjPtr(clsCustomer.GetDefaultInstance)
Debug.Print ObjPtr(pvtCustomer)
Set pvtCustomer = New clsCustomer
Debug.Print ObjPtr(clsCustomer.GetDefaultInstance)
Debug.Print ObjPtr(pvtCustomer)
Debug.Print IsDefaultInstance(clsCustomer.GetDefaultInstance, pvtCustomer)
Dim isDefault as Boolean
if defaultObject is compareObject then
  isDefault = True
End if
IsDefaultInstance = isDefault