2009-05-28 48 views
1

假设我有一个本身包含集合的某种集合;例如Dictionary(Of String,List(Of MyClass))。如果我要完全清除集合,它使任何意义清除父前清除每一个人的孩子集合,就像这样:清除收藏集 - 首先清除每个项目,或者只是一次清除所有项目?

For Each ListDef As KeyValuePair(Of String, List(Of MyClass)) In MasterDictionary 
    Dim ThisList As List(Of MyClass) = ListDef.Value 
    ThisList.Clear() 
Next 

MasterDictionary.Clear() 

或者这是否真的一事无成不是简单的多:

MasterDictionary.Clear() 

我在问是否有任何理由 - 性能,安全性,清晰度等 - 使用第一种方法。我自己通常使用第二种方法,因为我假设它隐式地实现了第一种方法。但我们都知道有时会有多危险;因此这个问题。

编辑:今天,在我自己的应用程序中,我看到了有力的证据表明第一种方法在某些情况下可能更可取。在我的应用程序中,我有一些全局集合(包含列表的字典,如上面的示例代码中所示),当用户单击标有“加载数据”的按钮时,这些集合将被填充。当用户点击“卸载数据”从头开始时,以前我正在使用上面的第二种方法清除这些集合。

问题是,当用户第二次点击“加载数据”时,应用程序会突然变得非常慢。最终它会完成收集再次,但在蜗牛的步伐。我无法弄清楚如何解决这个问题,直到我终于尝试了上面的第一种方法。现在重新加载和重新填充集合的过程与第一次加载集合的过程一样快。

根据到目前为止发布的答案,这听起来像我必须有“其他代码的地方”引用子集合;然而,它并不像我那样看着我。我引用这些孩子的唯一地方就是我重复他们父母的地方;如果父母被清除,那么他们应该没有孩子,代码是知道的,对吗?

希望有人可以帮助我理解这些引用是如何仍然徘徊在周围,或者我正在忽略的是怎么回事。

+0

根据您在问题中显示的代码示例,没有理由认为第一个片段与第二个片段的执行方式不同;在任何一种情况下,顶级字典都会在最后被清除,并且没有任何(据称)指的是原来在其中的任何元素。 解释第二次加载时性能差异的唯一方法是发生其他事情,但要确定是否有必要获取有关您的加载和卸载实际执行的更多信息。 – jerryjvl 2009-05-29 02:24:27

回答

4

在这两种情况下,您都没有处理子集合中包含的单个元素的处理问题。在这种情况下,两者应该相同。

如果其他代码直接引用任何单独的子集合,那么其中一个地方会有所不同。如果您在另一部分代码中持有对List(Of MyClass)之一的引用,则第一种方法将清除列表中的元素(并影响其他代码)。第二种方法不会这样做,因为它将单独保留List。

如果没有其他引用被保存,那么第二个方法就等待GC清除元素。在这两种情况下,各个参考资料都将由GC处理,因此性能差异可以忽略不计。就我个人而言,我会使用第二种方法,因为我相信它更清晰(并且写得更容易),并且在大多数情况下效果不会令人惊讶,尤其是如果您在其他地方使用列表时。

+0

自从我甚至研究过基于这个问题的代码以来,它已经很长时间了。回顾一下,我敢肯定,我一定是一直在做你在这里猜到的 - 在其他地方持有对儿童馆藏的引用 - 没有意识到这一点。老实说,原来的项目是如此的混乱。我刚刚开始,有很多东西需要学习。我现在接受这个答案是为了后人,因为我认为它代表了给这个场景中另一位开发人员的最明智的建议(我甚至不需要*这个代码来看看自己)。 – 2010-07-23 12:34:49

1

这取决于您的代码是如何使用的。

如果您在引用任何List(Of MyClass)的地方有其他代码,那么显然,那些列表将使用第一种方法为其他代码为空,而在第一种情况下则不会如此。

如果有任何性能差异,我不知道,我想找出最好的方法是尝试和分析它。有人可能会认为第一种方法最初使用的CPU能力稍高一些,但在GC轮回期间可能会少一些 - 但实际上这种情况下分析会有意义:)。

2

如果没有其他对'子'集合的引用,那么'父'集合上的Clear()将最终导致子集合(以及扩展中的项目)被清除。只要没有任何一个子集合的元素实现IDisposable,我就会说你是安全的,因为这意味着他们有一些资源被锁定,并且不妥善处理它们可能会导致问题。