在孩子仍然引用课程时自动终止课程

时间:2017-12-03 18:00:09

标签: vba excel-vba excel

我创建了一个类,其子级对其父级具有必要的引用。这意味着,当父类超出调用它的例程中的范围时,不会调用其终止代码,因为子代仍然持有对它的引用。

有没有办法终止父母而不必先手动终止孩子?

目前的解决方法是让父母的终止代码(包含终止孩子的代码)公开并从例程中调用它,但这并不理想,因为父母被终止两次(一次手动,一旦它离开调用者子范围)。但主要是我不想手动调用它

public class FileHandler : IHttpHandler
{

    public void ProcessRequest(HttpContext context)
    {
        if (context.Request.Files.Count > 0)
        {
            HttpFileCollection files = context.Request.Files;
            foreach (string key in files)
            {
                HttpPostedFile file = files[key];
                string fileName = file.FileName;
                fileName = context.Server.MapPath("~/uploads/" + fileName);
                file.SaveAs(fileName);
            }
        }
        context.Response.ContentType = "text/plain";
        context.Response.Write("File(s) uploaded successfully!");
    }

调用'Caller code Sub runTest() Dim testClass As parentClass Set testClass = New parentClass Set testClass = Nothing End Sub 'parentClass Private childrenGroup As New Collection Private Sub Class_Initialize() Dim childA As New childClass Dim childB As New childClass childA.Setup "childA", Me 'give name and parent reference to child class childB.Setup "childB", Me childrenGroup.Add childA 'add children to collection childrenGroup.Add childB End Sub Public Sub Class_Terminate() Set childrenGroup = Nothing Debug.Print "Parent terminated" End Sub 'childClass Private className As String Private parent As classParent Public Sub Setup(itemName As String, parentObj As classParent) Set parent = parentObj 'set the reference className = itemName End Sub Public Property Get Name() As String Name = className End Property Private Sub Class_Terminate() Debug.Print Name;" was terminated" 'only called when parent terminates child End Sub 打印

runTest()

2 个答案:

答案 0 :(得分:1)

审核了您的评论后,我仍然不相信您需要将父级传递给子级。如果您这样做的唯一原因是创建一种回调,那么您可能最好将事件委托类传递给子类而不是父类,然后简单地处理委托的事件你的父类。正如您所见,您当前的结构导致了一些对象处理问题,可以避免这些问题。

只需创建一个包含子事件的类。在这个例子中,我调用了类 clsChildEvents

Option Explicit

Public Event NameChange(obj As clsChild)

Public Sub NotifyNameChange(obj As clsChild)
    RaiseEvent NameChange(obj)
End Sub

现在你的代码仍然存在。关键的区别在于您将委托而不是父委托传递给子对象。

家长班:

Option Explicit

Private WithEvents mChildEvents As clsChildEvents
Private mChildren As Collection

Public Sub SetUp()
    Dim child As clsChild

    Set child = New clsChild
    child.SetUp "ChildA", mChildEvents
    mChildren.Add child

    Set child = New clsChild
    child.SetUp "ChildB", mChildEvents
    mChildren.Add child

End Sub

Private Sub mChildEvents_NameChange(obj As clsChild)
    Debug.Print "New name for "; obj.Name
End Sub

Private Sub Class_Initialize()
    Set mChildEvents = New clsChildEvents
    Set mChildren = New Collection
End Sub

Private Sub Class_Terminate()
    Debug.Print "Parent terminated."
End Sub

儿童班:

Option Explicit

Private mClassName As String
Private mEvents As clsChildEvents

Public Sub SetUp(className As String, delegate As clsChildEvents)
    Set mEvents = delegate
    Me.Name = className
End Sub
Public Property Get Name() As String
    Name = mClassName
End Property

Public Property Let Name(RHS As String)
    mClassName = RHS
    mEvents.NotifyNameChange Me
End Property

Private Sub Class_Terminate()
    Debug.Print mClassName; " terminated."
End Sub

然后你的模块代码:

Option Explicit

Public Sub Test()
    Dim parent As clsParent

    Set parent = New clsParent
    parent.SetUp

    Set parent = Nothing
End Sub

即时窗口输出如下:

  

ChildA的新名称

     

ChildB的新名称

     

家长终止。

     

ChildA终止。

     

ChildB终止。

答案 1 :(得分:0)

不,您不能通过简单地终止集合来自动终止孩子:

Public Sub Class_Terminate()
    Set childrenGroup = Nothing

当对象引用设置为Nothing时,它不会清除任何对象引用,并且它没有“RemoveAll”机制。

...而且我不会打赌'删除'这样做,一次一件。因此,您确实需要在成员中向后循环,完全是您试图避免的“手动”过程:

Public Sub Class_Terminate()
Dim i As Integer

    For i = childrenGroup.Count To 1 Step - 1
        Set childrenGroup(i) = Nothing
        childrenGroup.Remove i
    Next I

    Set childrenGroup = Nothing

我的建议是:使用Scripting.Dictionary对象而不是VBA集合:

Private childrenGroup As New Scripting.Dictionary

您需要对脚本运行时(或Windows脚本主机对象模型)的引用,您可能会对.Add Item, Key的更改顺序感到惊讶 - 您将肯定当您请求具有不存在的密钥的项目时会发生什么,我会感到惊讶。

尽管如此,这仍然有效。字典确实有一个RemoveAll方法,当你调用它时,清除其.Items中的所有引用:

Public Sub Class_Terminate()
    childrenGroup.RemoveAll

你确实需要调用RemoveAll - 如果字典超出范围,它就不会自动发生 - 但这就像你得到的那样接近。

另请注意,VBA在引用计数上运行:如果其他任何内容都引用了子项,则不会释放这些对象。