我有一个对象,其中包含其他对象的集合。我想通过调用基础对象的 dispose 方法来处理它们。集合的 dispose 方法将清除集合,但不会释放其中包含的单个对象。所以我需要我的基础对象循环遍历并处理每个子对象。最后一个细节是,我想确保集合在它包含的单个对象之前被处理掉。
我想我可以通过使用 Dispatcher.BeginInvoke 和低优先级来获得此行为。首先将集合的处置调用传递给它,然后遍历并处置每个单独的项目。 (伪)代码看起来像这样:
class Foo
{
FooCollection Children;
void Dispose()
{
//unsubscribe from data model events
CurrentDispatcher.BeginInvoke(Children.Dispose, ApplicationIdle, null);
foreach (Foo Child in Children)
{
CurrentDispatcher.BeginInvoke(Child.Dispose, ApplicationIdle, null);
}
}
}
class FooCollection
{
void Dispose()
{
//unsubscribe from data model events
this.Clear();
}
}
我走在正确的轨道上吗?还是我只是让自己处于竞争状态?即,在 foreach 完成对子进程的处理调用排队之前,调度程序是否有可能在集合上调用处理?有没有更好的方法来获得所需的行为?
可能值得注意的是,这些类中的每一个都公开事件,并将处理程序 Hook 到其他对象中。我的主要目标是确保在调用 dispose 时优雅地清理所有处理程序。
编辑(8/24): 这些类的实例订阅来自对象的事件,这些事件通常在应用程序的生命周期内持续存在。因此,持久对象维护对这些实例中的每一个的引用。我试图确保每个实例在不再需要实例时取消订阅持久对象的事件。
编辑 2(8/30): 这是 View 模型的一部分,表示从 Web 服务检索的数据层次结构。从 Web 服务检索数据的成本很高,因此返回的实际数据对象通常在应用程序的生命周期内被缓存。数据对象实现 ICollectionChanged 和 IPropertyChanged,相关的 View 模型对象订阅这些事件。应用程序的性质使得用户操作可能会导致 View 模型在 session 期间多次被丢弃和重新创建。数据的性质使得层次结构中通常有数千个节点必须在模型中表示。与此问题相关的主要问题是:
1) 确保丢弃的 View 模型取消订阅底层数据模型的事件
2) 确保以循环遍历废弃 View 模型的完整层次结构的方式完成,不会明显影响用户使用 View 模型的新实例。
我更新了代码示例以更准确地描述情况。所以问题依然存在。这段代码是否会给我预期的结果,即集合及其所有子项将在任何对象实际被处置之前排队等待处置,然后一段时间后线程将在空闲时间时开始处置它们?或者它是否会创建一个竞争条件,在我完成循环之前可能会处理集合?
大多数张贴者都关注收藏品被清除的事实,老实说,清除收藏品可能是不必要的,但这是一种习惯,我认为这是很好的整理工作。
最佳答案
查看此链接,它很好地解释了与事件处理程序相关的垃圾回收:What best practices for cleaning up event handler references?
这实际上取决于您的事件安排。如果您有从其他更持久的对象接收事件的对象,它们将坚持接收这些事件,直到事件源被 GC 处理。这表明如果你真的需要回收这个内存(这些对象有多大?你运行它的系统是什么?)你的 dispose 方法可能应该清除你连接到的事件(使用 -= 运算符)你处理完对象后,您必须自己调用此 Dispose
方法...
不需要清除集合 - 只需确保对您已完成的任何对象的所有引用都设置为 null。当不存在引用且无需维护事件处理程序时,GC 将收集该对象。
我也不会担心调度员..取消订阅事件不应该造成性能问题。
您不需要选择何时处置托管对象 - GC 可以。你不能在你处理它的 child 之前处理一个集合......因为你根本不能处理一个集合!您只能准备一个用于垃圾回收的托管对象,方法是
(1) 清除事件处理器和
(2) 摆脱所有对您已完成的对象的引用。
GC 会处理剩下的事情。
关于c# - 处理一个集合,然后处理它的内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7181047/