我有一个从常规.NET事件生成的Observable。 Observable很热 - 不是温暖 - 从某种意义上来说它甚至在任何订阅之前就开始产生价值,并且每当有人订阅它时它将收到最新产生的价值。我们将此命名为eventStream
。
然后我有另一个Observable,由另一个类公开,它代表一些状态流,所以每个新值都给出了该类管理的东西的当前状态。这个Observable也很热门。我们将其命名为stateStream
。
每当事件序列产生一个新值时,我想选择(我会说 sample ,但这可能会导致混淆)状态序列提供的最新值。这应该产生一个新的序列,组合这两个值,然后处理它们等等。
这是我提出的,但它似乎不起作用:
var eventStream = Observable.FromEventPattern<MyEventArgs>(/*...*/);
var stateStream = someDependency.SomeStateStream;
eventStream.Select(eventValue =>
stateStream
.Take(1)
.Select(stateValue => new { Event = eventValue, State = stateValue }))
.Switch()
.Do(value => _logger.Trace("{{ {0}, {1} }}", value.Event, value.State))
.Subscribe(value => /* do something */);
背后的基本原理取自我使用的其他类似场景,其中某些源生成的新值导致新订阅运行,因此返回 new Observable,最后{ {1}}使用IObservable<IObservable<...>>
或类似的运算符再次压缩成 one-dimensional IObservable。
但在这种情况下,从快速测试开始,似乎没有新的订阅,只生成了第一个Switch()
值。相反,每当stateStream
触发时,我都会选择第一个值(Take(1)
)。
AFAIK,eventStream
和CombineLatest
无法满足要求:每当两个序列中的一个提供新值时,Zip
就会触发;每当两个序列都有一个新值时,CombineLatest
就会触发,而这意味着当两个序列中最慢的值具有值时。 Zip
与And/Then/When
相同的原因也不应该是正确的。
我还检查了SO帖子combining one observable with latest from another observable,但我认为这不适用于此。只在我读过的一条评论中
[...]然后扫描就像一个CombineLatest,只过滤来自一方的通知
并且它听起来很熟悉,但我无法绕过那个。
答案 0 :(得分:4)
我认为你想要Observable.Sample()
stateSource.Sample(eventSource)
.Zip(eventSource,...)
答案 1 :(得分:1)
在我看来,您当前的解决方案实际上非常接近,但听起来您只需要交换eventStream
&amp; stateStream
可观察到.Take(1)
,然后移除stateStream
.Select(stateValue =>
eventStream
.Select(eventValue => new { Event = eventValue, State = stateValue }))
.Switch()
.Do(value => _logger.Trace("{{ {0}, {1} }}", value.Event, value.State))
.Subscribe(value => { /* do something */ });
。
试试这个:
stateStream
根据.StartWith(...)
的配置方式,您可能需要向其添加eventStream
以获取void logger([CallerMemberName] string methodName = "") { ... }
的初始值,但我认为这种方法可以满足您的要求。
答案 2 :(得分:0)
如果状态流尚未发出,则需要状态流的默认值。将此默认值作为参数传递给MostRecent
(我刚刚使用null
)并使用期望Zip
的{{1}}重载:
IEnumerable
答案 3 :(得分:0)
最新的(测试版)Rx.Net 2.3.0-beta2版本为WithLatestFrom
:
//Only emits when eventStream emits
eventStream.WithLatestFrom(stateStream.StartWith(defaultState),
(evt, state) => new {Event = evt, State = state})
.Subscribe(/*Do something*/);
如果没有,你可以使用(注意未经测试)填写它:
public static IObservable<TResult> WithLatestFrom<TLeft, TRight, TResult>(
this IObservable<TLeft> source,
IObservable<TRight> other,
Func<TLeft, TRight, TResult> resultSelector)
{
return source.Publish(os =>
other.Select(a => os
.Select(b => resultSelector(b,a)))
.Switch());
}
Source @JamesWorld的礼貌如果我没有记错的话。