【发布时间】:2014-12-13 22:12:28
【问题描述】:
如果我有三个 observables,我如何组合它们,以便当第一个发出新值时,我可以将它与其他两个发出的最新值组合在一起。重要的是,我们只产生组合后的新值当第一个 observable 具有新值时,无论其他两个是否发出新值,都可以观察到。
谢谢。
【问题讨论】:
标签: system.reactive
如果我有三个 observables,我如何组合它们,以便当第一个发出新值时,我可以将它与其他两个发出的最新值组合在一起。重要的是,我们只产生组合后的新值当第一个 observable 具有新值时,无论其他两个是否发出新值,都可以观察到。
谢谢。
【问题讨论】:
标签: system.reactive
您可以这样做(请注意,如果源 2 和 3 尚未发出,您将获得它们的默认值,并且我允许您有选择地提供这些默认值):
public static class ObservableExtensions
{
public static IObservable<TResult> CombineFirstWithLatestOfRest
<TSource1, TSource2, TSource3, TResult>(
this IObservable<TSource1> source1,
IObservable<TSource2> source2,
IObservable<TSource3> source3,
Func<TSource1, TSource2, TSource3, TResult> resultSelector,
TSource2 source2Default = default(TSource2),
TSource3 source3Default = default(TSource3))
{
var latestOfRest = source2.CombineLatest(source3, Tuple.Create);
return source1.Zip(latestOfRest.MostRecent(
Tuple.Create(source2Default, source3Default)),
(s1,s23) => resultSelector(s1, s23.Item1, s23.Item2));
}
}
使用示例:
var source1 = Observable.Interval(TimeSpan.FromSeconds(2));
var source2 = Observable.Interval(TimeSpan.FromSeconds(1));
var source3 = Observable.Interval(TimeSpan.FromSeconds(3.5));
var res = source1.CombineFirstWithLatestOfRest(source2, source3,
(x,y,z) => string.Format("1: {0} 2: {1} 3: {2}", x,y,z));
res.Subscribe(Console.WriteLine);
这里有一个微妙的问题,在您的场景中可能很重要。 CombineLatest 的一个有时不受欢迎的方面是它不会发出,直到它从每个贡献流中获得一个值。这意味着在上面的示例中,较慢的 source3 支持 source2 并且丢失了值。具体来说,返回的事件将具有 source2 和 source3 的默认值,直到 两者 各自发出至少一个事件。使用它们的默认值启动 source2 和 source3 是解决这种行为的一种方便的解决方法,我们可以摆脱它,因为它是驱动事件的 source1:
public static class ObservableExtensions
{
public static IObservable<TResult> CombineFirstWithLatestOfRest
<TSource1, TSource2, TSource3, TResult>(
this IObservable<TSource1> source1,
IObservable<TSource2> source2,
IObservable<TSource3> source3,
Func<TSource1, TSource2, TSource3, TResult> resultSelector,
TSource2 source2Default = default(TSource2),
TSource3 source3Default = default(TSource3))
{
source2 = source2.StartWith(source2Default); // added this
source3 = source3.StartWith(source3Default); // and this
var lastestOfRest = source2.CombineLatest(source3, Tuple.Create);
return source1.Zip(lastestOfRest.MostRecent(
Tuple.Create(source2Default, source3Default)), // now redundant
(s1,s23) => resultSelector(s1, s23.Item1, s23.Item2));
}
}
【讨论】:
MostRecent 运算符。