尽快结合请求并产生结果

时间:2017-05-23 11:07:47

标签: c# system.reactive reactive-programming

简短版本:如何在我自己的代码(https://github.com/akavache/Akavache/blob/501b397d8c071366c3b6783aae3e98695b3d7442/src/Akavache/Portable/JsonSerializationMixin.cs#L202)中实现像Akavache这样的GetAndFetchLatest方法 - 就像没有添加Akavache一样?

长版: 我有一个从磁盘返回T列表的方法,我有一个从HTTP服务返回相同类型List<T>的方法。 两者都异步包装为Task<List<T>>

在我的视图模型中,我只想调用1返回Observable<List<T>>的方法。

因此,在我的ViewModel中,我使用.Subscribe()方法更新UI。 实质上,我需要两次通知数据可用,订阅中的代码也将完成两次。

这个功能在Akavache中以GetAndFetchLatest方法的形式提供......但是我不太熟悉RX,以了解我如何使用我的2个数据方法调用来实现它。

注意:所以我不想等待这两项任务!我希望同时触发两者,并在数据返回后立即通知Observable

任何提示?

1 个答案:

答案 0 :(得分:3)

鉴于Task<List<T>> GetFromWeb()Task<List<T>> GetFromDisk(),答案很简单:

var merged = Observable.Merge(
    GetFromWeb().ToObservable(),
    GetFromDisk().ToObservable()
);

//Same thing using extension syntax
var simply = GetFromWeb().ToObservable()
    .Merge(GetFromDisk().ToObservable());

但是,这不会处理GetFromWebGetFromDisk之前完成的不太可能但可能的情况,在这种情况下,我假设您要忽略GetFromDisk的结果。为了解决这个问题,你需要一些体操:

public IObservable<T> Prioritize<T>(params IObservable<T>[] orderedByDescendingPriority)
{
    return orderedByDescendingPriority
        .Select((o, i) => o.Select(item => Tuple.Create(orderedByDescendingPriority.Length - i, item)))
        .Merge()
        .Select(t => new Func<Tuple<int, T, bool>, Tuple<int, T, bool>>(t2 => Tuple.Create(Math.Max(t2.Item1, t.Item1), t.Item2, t.Item1 >= t2.Item1)))
        .Scan(Tuple.Create(0, default(T), false), (t, f) => f(t))
        .Where(t => t.Item3)
        .Select(t => t.Item2);
}

var merged = Prioritize(
    GetFromWeb().ToObservable(),
    GetFromDisk().ToObservable()
);

修改

如果您始终希望GetFromDisk始终显示在GetFromWeb之前,那么这是一个简单的Concat操作。这是有效的,因为.NET任务会在您引用其功能后自动启动:

    var t1 = GetFromDisk();
    var t2 = GetFromWeb();

    var merged = Observable.Concat(
        t1.ToObservable(),
        t2.ToObservable()
    );