我创建了一个类,其子级对其父级具有必要的引用。这意味着,当父类超出调用它的例程中的范围时,不会调用其终止代码,因为子代仍然持有对它的引用。
有没有办法终止父母而不必先手动终止孩子?
目前的解决方法是让父母的终止代码(包含终止孩子的代码)公开并从例程中调用它,但这并不理想,因为父母被终止两次(一次手动,一旦它离开调用者子范围)。但主要是我不想手动调用它
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()
答案 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在引用计数上运行:如果其他任何内容都引用了子项,则不会释放这些对象。