Должен ли я всегда располагать подписками наблюдаемых? - PullRequest
0 голосов
/ 13 июня 2018

Должен ли я всегда располагать наблюдаемыми, когда ViewModel автоматически выходит из области видимости и не поддерживается ссылка на другие классы?

Небольшой пример:

public class TestViewModel : ReactiveObject
{
    public TestViewModel()
    {
        MyList = new ReactiveList<string>();
        MyList.ChangeTrackingEnabled = true;

        //Do I have to dispose/unsubscribe this?
        MyList.ItemChanged.Subscribe(_ => ...);

        //Or this?
        this.WhenAnyValue(x => x.MyList).Subscribe(_ => ...);
    }

    ReactiveList<string> _myList;
    public ReactiveList<string> MyList
    {
        get => _myList;
        set => this.RaiseAndSetIfChanged(ref _myList, value);
    }
}

Из моего пониманияподписки - это простые .NET-объекты.Без ссылки вне класса ViewModel.Поэтому, когда мой TestViewModel выходит из области видимости (то есть object больше никогда не используется и заменяется другим), GarbageCollector должен очистить все содержимое внутри ViewModel, поэтому у меня не длявручную вызовите Dispose для возвращенного IDisposables.

Правильно ли я здесь?

Редактировать
ReactiveList также может содержать другие объекты .NET,Этот пример не относится к неизменяемому типу строки.

Ответы [ 3 ]

0 голосов
/ 13 июня 2018

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

Один тестовый запуск с блоком using и один без:

class Program
{
    static void Main(string[] args)
    {
        //warmup types
        var vm = new TestViewModel();

        Console.ReadLine(); //Snapshot #1
        for (int i = 0; i < 1000; i++)
            Model();

        GC.Collect();
        Console.ReadLine();  //Snapshot #2
    }

    private static void Model()
    {
        using (var vm = new TestViewModel())
        {                
        }
    }
}

Нет утилизации вручную:

No disposal

Обе подписки утилизированы:

Both subscriptions disposed

Для 1 итераций различия незначительны, и GC выполняет свою работу.Различия в основном WeakReference типов.

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

Рекомендации ReactiveUI для того, когда удалять подписки

0 голосов
/ 13 июня 2018

Вы никогда не должны полагаться на сборщик мусора для правильной утилизации вашего объекта.

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

Dispose должен очистить управляемые ресурсы, а финализаторы должны очистить неуправляемые ресурсы, чтобы избежать утечек памяти.Шаблон Disposing(bool) будет вызывать как явный Dispose, так и только неуправляемый при сборке мусора.

Явный Dispose также позволяет выполнять очистку раньше, а не ждать, пока GC соберет.

В частности, для подписок, обработчиков событий и т. Д. Отсутствие очистки ссылок может означать, что когда GC действительно собирает, ссылки все еще существуют, и в этом случае объект вообще не будет собираться.

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

0 голосов
/ 13 июня 2018

Это мнение Кента Бугарта (одного из сопровождающих ReactiveUI) по этому вопросу:

Итак, гипотетически ... если вы используете WhenActivated в представлении, когда вы распоряжаетесьодноразовые что он возвращает?Вам придется хранить его в местном поле и сделать вид одноразовым.Но тогда, кто располагает мнением?Вам понадобятся ловушки платформы, чтобы знать, когда подходящее время для его использования - нетривиальный вопрос, если это представление повторно используется в сценариях виртуализации.Итак, вот что.

А как насчет того, когда вы выполняете реактивную команду?Вы храните одноразовые вещи, которые можете получить, чтобы потом «почистить»?Я догадываюсь, нет, и не зря.Когда выполнение завершается, все наблюдатели автоматически отписываются.Как правило, подписки на конвейеры с конечным сроком службы (например, через тайм-аут) не нужно удалять вручную.Утилизация такой подписки примерно так же полезна, как и утилизация MemoryStream.

. В дополнение к этому я обнаружил, что реактивный код в виртуальных машинах, в частности, имеет тенденцию манипулировать множеством одноразовых изделий.Хранение всех этих одноразовых принадлежностей и попытки утилизации имеют тенденцию загромождать код и заставлять саму ВМ быть одноразовой, что еще больше сбивает с толку.Perf - это еще один фактор, особенно для Android.

Так что мой совет проистекает из всего этого.Я считаю, что вызов тех подписок, которые требуют удаления путем их включения в WhenActivated, является наиболее прагматичным подходом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...