在一个集合上调用Clear方法是否会释放事件订阅?

5
我拥有一个集合。
private ObservableCollection<Contact> _contacts;

在我的类的构造函数中,我创建了它。
_contacts = new ObservableCollection<Contact>();

我有方法可以添加和删除我的集合中的项目。我想要跟踪实现了IPropertyChanged接口的实体在我的集合中所做的更改,因此我订阅了它们的PropertyChanged事件。

public void AddContact(Contact contact)
{
    ((INotifyPropertyChanged)contact).PropertyChanged += new PropertyChangedEventHandler(Contact_PropertyChanged);
    _contacts.Add(contact);
}

public void AddContact(int index, Contact contact)
{
    ((INotifyPropertyChanged)contact).PropertyChanged += new PropertyChangedEventHandler(Contact_PropertyChanged);
    _contacts.Insert(index, contact);
}

当我从集合中移除一个实体时,我会取消订阅PropertyChanged事件。据说这是为了允许实体被垃圾回收并避免内存问题。

public void RemoveContact(Contact contact)
{
    ((INotifyPropertyChanged)contact).PropertyChanged -= Contact_PropertyChanged;
    _contacts.Remove(contact);
}

所以,我希望这一切都很好。现在,我需要在我的一个方法中清除集合。我的第一个想法是调用_contacts.Clear()。然后我开始想,这是否会释放那些事件订阅?我需要创建自己的清除方法吗?类似这样:

public void ClearContacts()
{
    foreach(Contact contact in _contacts)
    {
        this.RemoveContact(contact);
    }
}

我希望这里的.NET C#专家们能够帮我解决疑惑,或告诉我哪里出了问题。
4个回答

4

Clear()方法不会移除事件处理程序。(注意,调用Clear()方法不会触发CollectionChanged事件,而Add()和Remove()会触发。)


1
回复:Clear()不引发PropertyChanged事件。你确定吗?查看Reflector中ObservableCollection<T>的代码显示,在ClearItems()方法内部,它调用了"Count"和"Item[]"的OnPropertyChanged,就像在Add/Remove中一样,Clear()调用了这个方法。 - Mara Morton
1
糟糕!我是指CollectionChanged事件。抱歉。 - Scott J

1

你可以为ObservableCollectionCollectionChanged事件设置一个处理程序,这对于在删除项目时取消挂接项目事件处理程序非常有效,并且当你执行Clear时会触发该事件,但问题是e.OldItems集合在Clear()时将为空。

所以同意@Michael的观点,要做到你想要的效果,你必须实现自己的Clear方法,可能作为扩展方法:

public static class Extensions
{
    public static void ClearEx(this ObservableCollection<object> collection)
    {
        //custom clear logic...   
    }
}

在你的清除函数中,你可以遍历这些项并在调用常规的Clear()函数之前清除事件处理程序。

0

这是来自 Reflector 的代码:

protected override void ClearItems()
{
    this.CheckReentrancy();
    base.ClearItems();
    this.OnPropertyChanged("Count");
    this.OnPropertyChanged("Item[]");
    this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}

它检查确保事件处理程序之一没有在循环调用它,调用基本CollectionClear函数,通知订阅者属性已更改,最后通知订阅者集合已更改。

在任何时候都不会清除任何事件处理程序。


0

Clear() 不会释放那些事件订阅。

最好自己编写一个 Clear 方法,遍历集合并删除事件处理程序,然后在集合上调用 Clear()

这样做的原因是,不要为每个项目调用 Remove(),因为在内部,Remove() 遍历集合以查找要删除的项目的索引,如果集合中有大量项目,则性能可能会受到影响。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接