【问题标题】:How do I combine three observables such that我如何组合三个可观察的,这样
【发布时间】:2014-12-13 22:12:28
【问题描述】:

如果我有三个 observables,我如何组合它们,以便当第一个发出新值时,我可以将它与其他两个发出的最新值组合在一起。重要的是,我们只产生组合后的新值当第一个 observable 具有新值时,无论其他两个是否发出新值,都可以观察到。

谢谢。

【问题讨论】:

    标签: system.reactive


    【解决方案1】:

    您可以这样做(请注意,如果源 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 运算符。
    • 谢谢詹姆斯。很有帮助的评论。
    猜你喜欢
    • 2020-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-30
    • 1970-01-01
    • 2016-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多