Как получить последнее значение от ReplaySubject‹T› перед завершением

Мне нужен способ получить самый последний элемент, добавленный в ReplaySubject, который соответствует определенным критериям. Пример кода ниже делает то, что мне нужно, но он не кажется правильным подходом:

static void Main(string[] args)
{
    var o = new ReplaySubject<string>();

    o.OnNext("blueberry");
    o.OnNext("chimpanzee");
    o.OnNext("abacus");
    o.OnNext("banana");
    o.OnNext("apple");
    o.OnNext("cheese");

    var latest = o.Where(i => i.StartsWith("b"))
        .Latest().First();

    Console.WriteLine(latest);

    Console.WriteLine("Press any key to exit");
    Console.ReadKey();
}

Выход:

banana
Press any key to exit

Сначала я пытался использовать .Where().TakeLast(1); однако теперь я знаю из предыдущего вопроса, что вы должны позвонить OnComplete() по этому вопросу, прежде чем TakeLast() что-либо вернет. Вызов OnComplete() для меня не вариант, потому что мне нужно держать этот поток открытым.

Может ли кто-нибудь подтвердить, является ли это наиболее эффективным подходом к тому, чего я пытаюсь достичь? Спасибо!

ИЗМЕНИТЬ

Обратите внимание, что я использую реактивные расширения, и образцы кода IEnumerable не будут работать.

ОБНОВЛЕНИЕ

Я склоняюсь к следующему коду, потому что считаю, что он не блокирует, если только кто-нибудь не скажет мне по-другому:

var latest = o.Where(i => i.StartsWith("b")).Replay(1);

using (latest.Connect())
     latest.Subscribe(Console.WriteLine);

person Matthew Scott    schedule 20.07.2011    source источник
comment
Прочитайте это? social.msdn.microsoft.com/ Форумы/en/rx/thread/   -  person Kevin P. Rice    schedule 20.07.2011
comment
@kevin: извините, я могу что-то упустить, но я не понимаю, как ссылка, которую вы разместили, имеет отношение к моей ситуации.   -  person Matthew Scott    schedule 20.07.2011
comment
В основном я нашел несколько сообщений с «похожими» проблемами (получение «последнего» элемента). Это показывает, что вам нужно вернуться на 2 элемента... другой может быть полезен здесь: social.msdn.microsoft.com/Forums/en-SG/rx/thread/ Но я уже выше головы, поэтому я остановлюсь. 3 удара! :)   -  person Kevin P. Rice    schedule 20.07.2011
comment
Имейте в виду, что при использовании решения UPDATE любая подписка, выполненная до вызова Connect, будет возвращать «чернику» в качестве первого значения и «банан» в качестве второго.   -  person James Hay    schedule 20.07.2011


Ответы (2)


Вы можете рассмотреть возможность использования BehaviorSubject<string>. Недостатком является то, что вы должны подписаться в начале, но это, вероятно, то, что вы все равно хотите сделать. Это должно обеспечить вам необходимую изоляцию.

var o = new ReplaySubject<string>();
var bs = new BehaviorSubject<string>(default(string));
o.Where(i => i.StartsWith("b")).Subscribe(bs);

o.OnNext("blueberry"); Console.WriteLine(bs.First());
o.OnNext("chimpanzee"); Console.WriteLine(bs.First());
o.OnNext("abacus"); Console.WriteLine(bs.First());
o.OnNext("banana"); Console.WriteLine(bs.First());
o.OnNext("apple"); Console.WriteLine(bs.First());
o.OnNext("cheese"); Console.WriteLine(bs.First());

Выход:

blueberry
blueberry
blueberry
banana
banana
banana
person StanislawSwierc    schedule 21.07.2011
comment
Я знал, что могу добиться этого с помощью BehaviorSubject, но базовый поток должен был оставаться ReplaySubject по другим причинам. Мне даже не пришло в голову создать BehaviorSubject и подписаться на базовый ReplaySubject. Спасибо! - person Matthew Scott; 25.07.2011

Пока вы довольны использованием этих блокирующих операторов (похоже, что вы), я бы рассмотрел возможность использования оператора MostRecent.

static void Main(string[] args)
{
    var o = new ReplaySubject<string>();

    o.OnNext("blueberry");
    o.OnNext("chimpanzee");
    o.OnNext("abacus");
    o.OnNext("banana");
    o.OnNext("apple");
    o.OnNext("cheese");

    var latest = o.Where(i => i.StartsWith("b"))
        .MostRecent("SomeDefaultValue")
        .First();

    Console.WriteLine(latest);

    Console.WriteLine("Press any key to exit");
    Console.ReadKey();
}
person James Hay    schedule 20.07.2011
comment
Я опубликовал пересмотр своего первоначального вопроса с неблокирующим способом выполнения этого. Я основывался на вашем исходном сообщении, которое вы так быстро удалили;) - person Matthew Scott; 20.07.2011
comment
@Matthew Glace - Да, я удалил его, потому что меня не устраивали разные результаты в зависимости от того, где вы подключились (до или после подписки). Не уверен, что на данный момент есть какой-то другой способ обойти это, но не хотел публиковать то, что меня не устраивало;) - person James Hay; 20.07.2011