Автосохранение с RX в C#

Я хочу реализовать функцию автосохранения. У меня есть два наблюдаемых:

  • IObservable<Unit> changes: создает элемент каждый раз, когда пользователь редактирует текст
  • IObservable<Unit> saves: генерирует событие сохранения каждый раз, когда нажимается кнопка сохранения.

Теперь я хочу объединить их в третий поток writeBack. У этого потока есть подписчик, который записывает текущий текст в базу данных.

Как создать поток writeBack, чтобы он выполнял следующие свойства?

  • несохраненное изменение записывается обратно, если в течение 3 секунд не произошло никаких изменений (например, дросселирование)
  • событие сохранения немедленно записывает последнее несохраненное изменение

Я хочу, чтобы только записывались несохраненные изменения. Я не хочу сохранять текст, если:

  • есть событие сохранения, но никаких изменений
  • два события сохранения подряд, но между ними нет изменений
  • есть событие сохранения между изменением и его автосохранением

person Streamfighter    schedule 22.01.2017    source источник


Ответы (1)


Это должно сделать это. Сначала мы определяем время, которое мы можем сэкономить:

var saveTriggers = changes.Throttle(TimeSpan.FromSeconds(3))
    .Merge(saves);

Затем мы отфильтровываем их, чтобы убедиться, что они соответствуют вашей логике: хотя бы одно редактирование между каждым сохранением, и сохранение не может быть первым. SkipWhile нужен только для того, чтобы убедиться, что сохранения, предшествующие изменениям, игнорируются. Scan подсчитывает количество изменений между каждым сохранением. Нам важно только, когда это число становится равным 0 (указывая на то, что сохранение было активировано). А DistinctUntilChanged отфильтровывает последовательные сохранения.

var actualSaves = saveTriggers.Select(_ => EventType.SaveTrigger)
    .Merge(changes.Select(_ => EventType.Edit))
    .SkipWhile(et => et == EventType.SaveTrigger)
    .Scan(0, (editCount, eventType) => eventType == EventType.SaveTrigger ? 0 : editCount + 1)
    .DistinctUntilChanged()
    .Where(count => count == 0)
    .Select(_ => Unit.Default);

и используя класс enum

enum EventType
{
    SaveTrigger,
    Edit
}
person Shlomo    schedule 23.01.2017
comment
Спасибо, он делает именно то, что должен. Я нашел свое собственное решение, но оно использовало Windows с отложенными потоками и было слишком сложным. Этот намного проще. Хорошая идея использовать Scan. - person Streamfighter; 25.01.2017
comment
Спасибо. Каждый раз, когда вы смотрите на логику с точки зрения истории, Scan должно быть первым, на что вы обращаете внимание. - person Shlomo; 25.01.2017