Удаление коллекции VB6 не запускает Class_Terminate - PullRequest
4 голосов
/ 27 октября 2009

прошу прощения заранее; это длинный вопрос. Я пытался упростить столько, сколько смогу, но это все еще более многословно, чем мне хотелось бы видеть.

В каком-то устаревшем коде у нас есть коллекция VB6. Эта коллекция добавляет объекты с помощью метода .Add и удаляет их с помощью метода .Remove. Тем не менее, с помощью трассировки я вижу, что иногда, когда вызывается .Remove, кажется, что класс завершения для объекта не вызывается. Но это не соответствует; это случается очень редко, и я не могу выделить обстоятельства, при которых он не срабатывает, класс прекращается.

Рассмотрим следующий демонстрационный код:

Option Explicit
Private Const maxServants As Integer = 15
Private Const className As String = "Master"
Private Sub Class_Initialize()
    Debug.Print className & " class constructor "
    Set g_coll1 = New Collection
    Dim i As Integer
    For i = 1 To maxServants
        Dim m_servant As Servant
        Set m_servant = New Servant
        m_servant.InstanceNo = i
        g_coll1.Add Item:=m_servant, Key:=CStr(i)
        Debug.Print "Adding servant " & m_servant.InstanceNo
    Next
End Sub
Private Sub Class_Terminate()
    Dim i As Integer

    For i = maxServants To 1 Step -1
        g_coll1.Remove (CStr(i))
    Next

    Debug.Print className & " class terminator "
    Set g_coll1 = Nothing
    Exit Sub

End Sub

и

Option Explicit
Private Const className As String = "Servant"
Private m_instanceNo As Integer
Private Sub Class_Initialize()
    m_instanceNo = 0
    Debug.Print className & " class constructor "
End Sub
Public Property Get InstanceNo() As Integer
    InstanceNo = m_instanceNo
End Property
Public Property Let InstanceNo(newInstanceNo As Integer)
    m_instanceNo = newInstanceNo
End Property
Private Sub Class_Terminate()
    Debug.Print className & " class terminator for " & CStr(Me.InstanceNo)
End Sub

и это код тестового жгута:

Option Explicit
Global g_coll1 As Collection
Public Sub Main()
    Dim a As Master
    Set a = New Master
End Sub

Теперь для каждого запуска всегда вызывается class_terminate Servant. И я не вижу ничего в производственном коде, который бы содержал ссылку на объект в коллекции.

1.) Есть ли способ принудительно завершить класс при удалении? То есть я могу вызвать Obj.Class_Terminate и быть уверенным, что он будет работать каждый раз?

2.) В моем рабочем коде (и моем небольшом тестовом приложении) классы помечены как «Instancing - 5 MultiUse». Я понимаю, что это может быть какая-то проблема с многопоточностью; Есть ли эффективный способ доказать (или опровергнуть), что причиной этой проблемы является многопоточность - какой-то вид трассировки, который я мог бы добавить, или какой-то другой вид теста, который я мог бы выполнить?


РЕДАКТИРОВАТЬ: В соответствии с проницательным комментарием MarkJ ниже, я должен добавить, что опубликованный выше тест и производственный код являются ActiveX exe - одна из причин, почему я спрашиваю о многопоточности.

1 Ответ

3 голосов
/ 27 октября 2009

У нас была похожая проблема, но там, где мы могли отследить отсутствие завершения объектов до экземпляра, хранящегося в другом месте нашего приложения.

В конце концов, мы должны были написать наш метод завершения следующим образом:

Private Sub Class_Terminate()
    Terminate
End Sub

Public Sub Terminate()
    'Do real termination in here'
End Sub

Поэтому, когда вы действительно хотите, чтобы класс был завершен (т.е. когда вы вызываете g_coll1.Remove), вы также можете вызвать Terminate для удерживаемого объекта.

Я думаю, что вы также можете сделать Class_Terminate публичным, но, на мой взгляд, это немного уродливо.

В отношении вашей точки зрения (2), я думаю, что это очень маловероятно, это проблема с потоками, но я не могу придумать хорошее доказательство / тестирование на моей голове. Я полагаю, что вы можете рассмотреть одну очень удобную вещь: вы вручную используете потоки в своем приложении? VB6 не выполняет много потоков автоматически ... (см. Правку ниже)

[ Edit ] MarkJ сообщает нам, что очевидно, что сборка как приложения ActiveX означает, что VB6 автоматически выполняет многопоточность. Кто-то еще должен будет изучить последствия этого, так как я не был знаком с этим!

...