Сохранение ссылок на `IDisposable` при использовании Reactive Extensions для .NET: всегда, никогда или иногда? - PullRequest
16 голосов
/ 08 марта 2011

До сих пор я усердно хранил все ссылки на IDisposable, возвращаемые любым методом .Subscribe(...), .Connect(...) и т. Д. В Rx.Я сделал это из-за своего страха, что сборщики мусора избавятся от одноразового использования, если я не сохраню ссылку.

Однако я провел тест в LINQPad, где сделал несколько вызовов GC.Collect() на.Subscribe(...) где я не сохранил ссылку и угадайте что?Мир не закончился, и подписка подошла к завершению.

В ходе дальнейшего тестирования я обнаружил, что моя подписка была уничтожена сразу после .OnComplete() без моего вмешательства.

Это заставляет меня понятьчто, по крайней мере для .Subscribe(...), единственной причиной сохранения ссылки на подписку является принудительное завершение подписки до ее нормального завершения.Это больше похоже на токен отмены.

Итак, все ли одноразовые расходные материалы Rx используются для отмены, а не для сохранения в живых?

Каковы же правила удержания на IDisposable?

Ответы [ 4 ]

18 голосов
/ 10 марта 2011

Нет необходимости держаться за объекты IDisposable, если вы не хотите отписаться от наблюдаемого источника в будущем.Аналогично для методов Schedule в IScheduler, чьи возвращенные объекты IDisposable можно использовать для отмены запланированного действия.

Сборщик мусора не заботится непосредственно об объекте IDisposable, и мы не реализуем финализаторы ни для одного из наших объектовтак что, в сущности, в мире Rx управление пожизненными подписками и т. д. полностью зависит от вас.Если хотите, сравните его с дескрипторами Win32, причем Dispose является моральным эквивалентом CloseHandle.

Общая информация: в какой-то момент во время разработки Rx отменяемые операции возвращали действие, вызов которого вызвал бы отмену.Весьма функционально вдохновленный по своей природе, но менее очевидный для некоторых.Итак, мы решили использовать интерфейс, который уже представляет понятие управления ресурсами, и IDisposable был очевидным выбором.Это говорит о том, что оно немного отличается от обычного использования интерфейса где-либо еще в .NET Framework:

  • Вы будете часто просто бросать объект IDisposable на пол, особенно для бесконечных последовательностей, которые вы никогда не отмените.from.
  • В большинстве случаев вы не будете использовать оператор using для объектов Rx IDisposable из-за присущей асинхронному характеру структуры.

Надеюсь, это поможет,

-Барт (команда Rx)

8 голосов
/ 09 марта 2011

IDisposable, возвращаемое IScheduler.Schedule(), полезно только в том случае, если вы хотите отменить запланированное действие (то есть, до , когда это произошло)

IDisposable, возвращаемое IObservable.Subscribe и IConnectableObservable.Connect эквивалентны, в этом случае уничтожение любого из них приведет к прекращению подписки на наблюдаемый источник.

Что касается сбора мусора, в то время как Rx усложняет его измерение, он все еще ограничен правиламиГК.Если источник вашей наблюдаемой имеет корни (например, событие элемента управления пользовательского интерфейса), то вам не нужно беспокоиться о том, что это GC'd.

Если ваш источник - Observable.Interval или что-то ещев основном это рекурсивный вызов IScheduler, тогда планировщик должен поддерживать его в рабочем состоянии (т. е. пул потоков, пул задач или диспетчер), поскольку наблюдаемое связано с планировщиком (через IScheduler.Schedule).

4 голосов
/ 08 марта 2011

Ну, во-первых, я считаю важным отметить, что сборщик мусора и утилизация объектов / интерфейс IDisposable полностью отделены друг от друга - в частности сборщик мусора никогда не удалит объект напрямую, вызвав метод DisposeIDisposable (если финализатор для этого объекта не сделает это сам).

Что касается того, когда вам следует удерживать IDisposable, вы должны поддерживать ссылку на любой IDisposable объект, который вам нуженраспоряжаться - звучит так, будто я констатирую очевидное, и это потому, что я есть!:-).Если время жизни одноразовых объектов не превышает одного метода, обычно используется ключевое слово using:

using (var myDisposableObject = GetSomeDisposableObject())
{
    myDisposableObject.DoThings();
}

Это ограничивает область действия myDisposableObject (что помогает избежать попыток использовать объект, который был удален) и обеспечивает правильное удаление объекта, даже если выдается исключение.

Это может быть тем, что для определенного класса / API вам не нужно (или не должно быть)) распоряжаться объектом, который вам возвращен, однако полностью зависит от API / класса, который возвратил этот одноразовый объект.

2 голосов
/ 08 марта 2011

Да, IDisposable, который возвращается из Subscribe(), необходим только для отмены подписки ().Конечно, вызов Unsubscribe () не существует, вместо этого вы бы Dispose() при необходимости.

...