Отменить подписку на события в watchableCollection

Предположим, что у меня есть наблюдаемый класс классов:

CustomClassName testClass = new CustomClassName();
ObservableCollection<CustomClassName> collection = new ObservableCollection<CustomClassName>();
testClass.SomeEvent += OnSomeEvent;
collection.add(testClass);

Когда я удалю элементы из коллекции, мне нужно вручную отказаться от подписки на события (OnSomeEvent) или оставить ее для GC? И какой лучший способ отказаться от подписки?

Ответ 1

Если вы ожидаете, что ваш товар будет собран, тогда вам нужно отказаться от подписки.

Для этого обычный способ:

collection.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(collection_CollectionChanged);

// ...
// and add the method
void collection_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
    if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove)
    {
        foreach (var it in e.OldItems) {
            var custclass = it as CustomClassName;
            if (custclass != null) custclass.SomeEvent -= OnSomeEvent;
        }
    }
}

Ответ 2

Вам не нужно отказываться от подписки в обычном случае.

Абонент событий не может предотвратить сбор издателя (testClass), но может произойти обратное. Я не вижу ничего, поддерживая testClass живым, кроме ObservableCollection.

testClass.SomeEvent += this.OnSomeEvent;

testClass поддерживает this живое, потому что this хранится в списке вызовов testClass.SomeEvent (так что OnSomeEvent вызывается, когда есть SomeEvent). this не будет поддерживать testClass вживую, подписав testClass событие.

В следующем коде obj удаляется из коллекции, и это мусор, собранный без отмены подписки, вы можете попробовать запустить код, чтобы увидеть результат:

void Main()
{
    var obj = new BackgroundWorker();
    obj.DoWork += OnSomeEvent;
    var oc = new ObservableCollection<object>{ obj };

    WeakReference objRef = new WeakReference(obj);
    Console.WriteLine(objRef.IsAlive);

    oc.Remove(obj);
    obj = null;
    GC.Collect();

    Console.WriteLine(objRef.IsAlive);
}

private void OnSomeEvent(object sender, DoWorkEventArgs e)
{   
    Console.WriteLine("work");
}

Вывод:

True
False

Вы можете заглянуть в аналогичный вопрос.