Преобразование реактивных расширений из IObservable в IEnumerable

2

Учитывая Наблюдаемый, который начнет толкать события после вызова Subscribe. Как последовательность может быть преобразована в IEnumerable.

В 2010 году Джон Скит написал о своих первых впечатлениях от RX и написал это, что было бы эквивалентно тому, что мне нужно.

public static List<T> ToList<T>(this IObservable<T> source) 
{ 
    List<T> ret = new List<T>(); 
    source.Subscribe(x => ret.Add(x)); 
    return ret; 
}

https://codeblog.jonskeet.uk/2010/01/16/first-encounters-with-reactive-extensions/

Хотя это решение будет работать, кажется, что должен быть лучший способ.

То, что нас действительно интересует, - это способность await наблюдаемого таким образом, который ведет себя аналогично Subscribe.

await observable.ToList()

Однако, похоже, это не работает для меня.

Я также рассмотрел эти два метода

observable.ToEnumerable
observable.Next

Немного больше информации

Я планирую использовать это, чтобы написать некоторые модульные тесты.

  1. Я использую ReplaySubject и выполняю последовательность действий с заменой теста.
  2. Звонки на замену записываются через OnNext.
  3. Я могу получить список вызовов и Assert, они верны.
  • 0
    Статья Джона Скита была написана в 2010 году, когда Rx был всего лишь исследовательским проектом, а async/await было два года в будущем. К 2011 году в Observable появился собственный ToList() расширения ToList()
  • 0
    @PanagiotisKanavos, чтобы вы могли изменить IObservable <T> на IObservable <IList <T >> IObservable<IList<TSource>> ToList<TSource>(this IObservable<TSource> source) MSDN И Даниэль спрашивает о IObservable <T> на IEnumerable < T> преобразование
Показать ещё 1 комментарий
Теги:
system.reactive

2 ответа

3
Лучший ответ

Интересно, что реализация мистера Скита довольно горькая. Он не блокируется, поэтому будет накачивать значения только в списке, если источником является объект воспроизведения (или аналогичный). Поэтому для большинства наблюдаемых последовательностей это просто возвращает пустой список. Я уверен, что Джон это знает, но, возможно, заблудился в переводе.

ToList() - это то, что вы хотите, поэтому я предполагаю, что, возможно, вы не закончили? Если вам требуется только определенное количество элементов, тогда Take(x).ToList() будет достаточно.

  • 0
    Я настоятельно рекомендую отредактировать этот ответ. Статья Джона Скита была написана в 2010 году, когда не было async/await . Reactive Extensions тогда были просто исследовательским проектом. Нет ToList() ,
2

EDIT:

Если вы не можете завершить поток, как описано ниже, то использование await будет ждать бесконечно. Я бы испытал другим способом. Вы можете посмотреть пакет Nuget Microsoft.Reactive.Testing, который содержит несколько мощных инструментов тестирования. Или просто используйте Subscribe и утверждайте там.


await ожидает наблюдаемого завершения или ошибки. Вероятно, вам просто нужно добавить вызов OnCompleted в ваш ReactiveSubject и все будет в порядке. Для меня работает следующий код:

var rs = new ReplaySubject<int>();

rs.OnNext(1);
rs.OnNext(2);
rs.OnNext(3);
rs.OnCompleted();
var l = await rs.ToList();

//l is equivalent to  new List<int>() {1, 2, 3};
  • 0
    Я просто понял, что у меня нет возможности завершить поток
  • 0
    Обновленный ответ.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню