Я нахожусь на ранних этапах изучения Rx и наткнулся на класс Subject. Я не совсем понимаю, почему этот класс существует. Я понимаю, что он реализует как IObservable, так и IObserver, но для чего используются субъекты?
Насколько я могу судить, они могут действовать как прокси между источником и группой подписчиков, но не могут ли подписчики просто подписаться непосредственно на источник? Когда я вижу экземпляры Subject, используемые в качестве наблюдаемого и наблюдателя, я путаюсь.
Я уверен, что просто не улавливаю некоторые основные факты, но я не знаю, что Субъект привносит в игру. Думаю, я ищу какой-то базовый (но, надеюсь, реальный) пример того, когда субъекты полезны, а когда нет (поскольку я также читал, что субъекты обычно не используются, заменены на Observable.Create).
Ответ 1 · рейтинг 1 · JerKimball
Во-первых, многие люди скажут вам, что Subject<T> не подходит, так как это противоречит некоторым другим принципам/шаблонам в структуре Rx.
Тем не менее, они действуют либо как IObservable, либо как IObserver, поэтому вы получаете от них некоторую полезную функциональность - я обычно использую их на начальных этапах разработки для:
Своего рода "точка отладки", где я могу подписаться на цепочку IObservable, встроенную в Subject<T>, и проверять содержимое с помощью отладчика.
"Наблюдаемый по запросу", где я могу вручную вызвать OnNext и передать данные, которые я хочу ввести в поток
Раньше использовал их, чтобы воспроизвести то, что сейчас делает ConnectableObserable - механизм "трансляции" для нескольких подписчиков на один Observable, но теперь это можно сделать с Publish.
Промежуточный слой между разрозненными системами; опять же, теперь это в значительной степени не нужно с различными расширениями FromAsync, FromEvent, но их все еще можно использовать как таковые (в основном, "старая" система вводит события в Subject<T> через OnNext, а затем в обычный поток Rx.
Ответ 2 · Rajnikant
Использование субъектов означает, что теперь мы управляем состоянием, которое потенциально мутирует. Мутационное состояние и асинхронное программирование очень трудно сделать правильно. Кроме того, многие операторы (методы расширения) были тщательно написаны, чтобы обеспечить правильное и согласованное время жизни подписок и последовательностей. Когда вы вводите предметы, вы можете сломать это.
Существенным преимуществом метода Create по сравнению с субъектами является то, что последовательность будет оцениваться лениво.
В этом примере мы показываем, как мы можем сначала вернуть последовательность с помощью стандартного блокирующего вызова с нетерпеливым вычислением, а затем мы покажем правильный способ вернуть наблюдаемую последовательность без блокировки с помощью отложенного вычисления.
Пример ниже будет заблокирован как минимум на 1 секунду, прежде чем они даже получат IObservable, независимо от того, действительно ли они подписаны на него или нет.
private IObservable<string> BlockingMethod()
{
var subject = new ReplaySubject<string>();
subject.OnNext("a");
subject.OnNext("b");
subject.OnCompleted();
Thread.Sleep(1000);
return subject;
}
Где, как в примере bleow, потребитель немедленно получает IObservable и будет нести затраты на спящий режим только в том случае, если они подпишутся.
private IObservable<string> NonBlocking()
{
return Observable.Create<string>(
(IObserver<string> observer) =>
{
observer.OnNext("a");
observer.OnNext("b");
observer.OnCompleted();
Thread.Sleep(1000);
return Disposable.Create(() => Console.WriteLine("Observer has unsubscribed"));
//or can return an Action like
//return () => Console.WriteLine("Observer has unsubscribed");
});
}