Что делать с утилитами IObservers? - PullRequest
6 голосов
/ 17 января 2012

Я использую Reactive Extensions для удобной обработки событий в моих ViewModels (приложения Silverlight и / или Wp7). Для простоты, скажем, у меня есть строка, подобная этой, в ctor моей виртуальной машины:

Observable.FromEvent<PropertyChangedEventArgs>(
                            h => MyObject.PropertyChanged += h, 
                            h => MyObject.PropertyChanged -= h)
    .Where(e=>e.PropertyName == "Title")
    .Throttle(TimeSpan.FromSeconds(0.5))
    .Subscribe(e=>{/*do something*/});

возвращает объект IDisposable, , который при удалении откажется от подписки. (Прав ли я в этом предположении?)
Если я не буду ссылаться на него, рано или поздно он будет собран, и мой обработчик будет отписан.

У меня обычно есть List<IDisposable> в моей виртуальной машине, и я добавляю к ней подписки, но я чувствую себя грязно из-за этого, как будто я делаю что-то неправильно в Rx.

Какова лучшая практика, рекомендуемая схема в подобных ситуациях?

Ответы [ 3 ]

9 голосов
/ 17 января 2012

Ваше первое предположение верно, IDisposable для отписки.Однако вам не нужно хранить ссылку на IDisposable, чтобы предотвратить сбор вашего наблюдателя.IObservable должен будет сохранить ссылку на наблюдателя, чтобы иметь возможность вызывать его методы, таким образом поддерживая наблюдателя в живых, пока наблюдаемая жива.

Проницательный читатель поймет, что я несколько задаю вопрос, потому что я предположил, что наблюдаемое не будет собрано.Чтобы решить эту проблему, давайте сделаем некоторые разумные предположения о том, что происходит за кулисами.Первая наблюдаемая подписка на событие.Это означает, что объект с событием имеет ссылку на нашего наблюдателя с момента, когда мы подписываемся на момент, когда мы отписываемся.Поскольку операторы Rx должны в какой-то момент подписаться на свои источники, можно предположить, что наблюдатель события имеет ссылку на наблюдателя Where, который имеет ссылку на наблюдателя Throttle, который, конечно, ссылается на нашего конечного наблюдателя.

Поскольку мы не могли отписаться, это связывает жизнь наблюдателя с жизнью объекта с событием.Без полного знания вашей программы, это все, что я могу пройти дальше по цепочке, но я думаю, вам будет достаточно определить время жизни наблюдаемого.

Это фактически указывает на потенциальную "память"утечка », которую вы можете иметь со стандартными событиями .NET, объектами, поддерживающими всех своих подписчиков событий, что приводит к вашему второму вопросу.Если вы не сохраните ссылку на IDisposable, вы никогда не сможете отписаться от события, и ваш объект будет продолжать получать уведомления даже после закрытия представления, с которым он связан.Если источник события не живет дольше, чем представление, это может не быть проблемой, но Я рекомендую использовать одноразовые .

В этом нет ничего "un-Rx", и Rx даже включает хороший класс для использования в качестве альтернативы List, если хотите, System.Reactive.Disposables.CompositeDisposable.

6 голосов
/ 18 января 2012

Гедеон здесь неверен. Семантика того, как Rx использует IDisposable, отличается от типичной .NET. IDisposable возвращается из Subscribe, если вы хотите отменить подписку раньше , чем конец IObservable. Если вы не хотите этого делать, усложнять свой код всеми дополнительными одноразовыми средствами управления не нужно.

0 голосов
/ 17 января 2012

Обычной практикой является реализация интерфейса IDisposable и размещение ваших одноразовых элементов здесь.

...