先处理集合,然后处理它的内容

本文关键字:后处理 然后 处理 集合 | 更新日期: 2023-09-27 18:06:29

我有一个对象,它包含其他对象的集合。我想通过调用基对象上的dispose方法来处理它们。集合的dispose方法将清除集合,但它不释放它所包含的单个对象。所以我需要基对象循环遍历并处理每个子对象。最后一个细节是,我想确保在处理集合所包含的单个对象之前先处理集合。

我想我可以通过使用Dispatcher获得这个行为。BeginInvoke和低优先级。首先将集合的dispose调用传递给它,然后循环遍历并处置每个单独的项。(伪)代码看起来像这样:

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();
    }
}

我讲对了吗?或者我只是给自己设置了一个竞争条件?也就是说,Dispatcher是否有可能在foreach完成对子线程的dispose调用队列之前对集合调用dispose ?是否有更好的方法来获得期望的行为?

可能值得注意的是,这些类中的每个都公开事件,并将处理程序挂钩到其他对象。我的主要目标是确保在调用dispose时优雅地清理所有处理程序。

编辑(8/24):这些类的实例从对象中订阅事件,这些事件通常在应用程序的整个生命周期中持续存在。因此,持久对象维护对每个实例的引用。我试图确保每个实例在不再需要实例时取消订阅持久性对象的事件。

编辑2 (8/30):这是视图模型的一部分,它表示从web服务检索到的数据层次结构。从web服务检索数据的成本很高,因此返回的实际数据对象被缓存,通常在应用程序的整个生命周期内都是如此。数据对象实现了ICollectionChanged和IPropertyChanged,所讨论的视图模型对象订阅了这些事件。应用程序的性质是这样的:用户操作可能会导致视图模型被丢弃,并在会话期间多次重新创建。数据的性质是这样的,在层次结构中通常会有几千个节点,这些节点必须在模型中表示。与这个问题相关的主要关注点是:

1)确保被丢弃的视图模型取消订阅底层数据模型的事件

2)确保循环遍历丢弃的视图模型的完整层次结构不会明显影响用户使用视图模型的新实例。

我已经更新了代码示例以更准确地表示情况。所以问题依然存在。这段代码是否会给我预期的结果,在任何对象实际被处置之前,集合及其所有子集合将排队等待处置,然后一段时间后,线程将在有空闲时间时开始处置它们?或者它是否会创建一个竞争条件,在我完成循环之前可能会处理集合?

大多数海报关注的是清理收集的事实,老实说,清理收集可能是不必要的,但这是一种习惯,我认为这是一种很好的管理

先处理集合,然后处理它的内容

查看这个链接,它很好地解释了关于事件处理程序的垃圾收集:清理事件处理程序引用的最佳实践是什么?

这真的取决于你的事件如何排列。如果您有对象从其他更持久的对象接收事件,它们将继续接收这些事件,直到事件源被GCed。这表明,如果您确实需要回收这些内存(这些对象有多大?),则dispose方法可能应该清除连接到的事件(使用-=操作符)。你在什么系统上运行这个程序?)当你用完这些对象后,你必须自己调用这个Dispose方法…

清除集合是没有必要的——只要确保对任何对象的所有引用都被设置为null。当不存在引用且不需要维护事件处理程序时,GC将收集对象。

我也不会担心调度员…取消订阅事件不会造成性能问题。

你不能选择何时处置托管对象——由GC来做。在处置其子集合....之前,不能处置集合因为你根本不能处理一个集合!您只能为垃圾收集准备一个托管对象,实现方法是

(1)清除事件处理程序和

(2)去掉所有对已经完成的对象的引用。

GC将处理其余的工作。

您将无法保证调度程序调用dispose的顺序。鉴于此,我认为最好先处理集合中的单个项,然后在集合上调用dispose。

如果在foreach循环完成之前清除集合,则可能以异常结束。

我建议您换个设计。请注意,这不是最终代码,只是为了展示这个想法。

class Bar:IDisposable
{
    void Dispose()
    {
    //do some logic
    }
}
class BarCollection:List<Bar>,IDisposable
{
    void Dispose()
    {
        foreach(Bar bar in this){
            bar.Dispose();
        }
    }
}
class Foo
{
    BarCollection Children;
    void Dispose()
    {
        CurrentDispatcher.BeginInvoke(Children.Dispose, ApplicationIdle, null);
    }
}