【问题标题】:Does The Clear Method On A Collection Release The Event Subscriptions?集合上的 Clear 方法是否会释放事件订阅?
【发布时间】:2010-03-19 21:32:57
【问题描述】:

我有一个收藏

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# 专家之一可以为我解决这个问题或告诉我我做错了什么。

【问题讨论】:

    标签: c# collections


    【解决方案1】:

    Clear() 不会删除事件处理程序。 (还要注意,调用 Clear() 不会像 Add() 和 Remove() 那样触发 CollectionChanged 事件。)

    【讨论】:

    • RE:Clear() 没有提示 PropertyChanged。您确定吗?使用 Reflector 查看 ObservableCollection 的代码表明它正在为“Count”和“Item[]”调用 OnPropertyChanged,这与在 ClearItems() 方法中的 Add/Remove 中相同,Clear() 调用该方法。
    • 天啊!我的意思是 CollectionChanged 事件。对不起。
    【解决方案2】:

    您可以为ObservableCollectionCollectionChanged 事件提供一个处理程序,这对于在删除项目事件处理程序时解除挂钩非常有效,并且在您执行Clear 时确实会触发它,但问题是是e.OldItems 集合在Clear() 上为空。

    所以要同意@Michael,做你想做的事,你必须实现自己的 Clear 方法,也许作为扩展方法:

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

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

    【讨论】:

      【解决方案3】:

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

      最好使用您自己的 Clear 方法来遍历集合,删除事件处理程序,然后在集合上调用 Clear()

      之所以这样做,而不是为每个项目调用 Remove(),是因为在内部,Remove() 会遍历集合以找到您要删除的项目的索引,如果有集合中的大量项目。

      【讨论】:

        【解决方案4】:

        这是来自 Reflector 的代码:

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

        它检查以确保其中一个事件处理程序没有在循环中调用它,调用基础CollectionClear 函数,通知订阅者属性已更改,最后通知订阅者收藏已更改。

        它绝不会清除任何一个事件处理程序。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-06-18
          • 2011-08-29
          • 1970-01-01
          • 2021-02-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-10-29
          相关资源
          最近更新 更多