当另一个Observable产生任何值时,选择Observable最新值

时间:2015-06-29 20:19:55

标签: c# system.reactive

我有一个从常规.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,eventStreamCombineLatest无法满足要求:每当两个序列中的一个提供新值时,Zip就会触发;每当两个序列都有一个新值时,CombineLatest就会触发,而这意味着当两个序列中最慢的值具有值时。 ZipAnd/Then/When相同的原因也不应该是正确的。

我还检查了SO帖子combining one observable with latest from another observable,但我认为这不适用于此。只在我读过的一条评论中

  

[...]然后扫描就像一个CombineLatest,只过滤来自一方的通知

并且它听起来很熟悉,但我无法绕过那个。

4 个答案:

答案 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的礼貌如果我没有记错的话。