Отменить подписку на события в 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
Вы можете заглянуть в аналогичный вопрос.