Observable.Where与异步谓词

时间:2014-08-13 21:14:54

标签: c# async-await system.reactive

是否有一种方便的方法可以使用异步函数作为可观察对象的Where运算符的谓词?

例如,如果我有一个很好的整洁但可能长时间运行的函数定义如下:

Task<int> Rank(object item);

是否有将其传递给Where并保持异步执行的技巧?如:

myObservable.Where(async item => (await Rank(item)) > 5)

过去,当我需要这样做时,我已经使用SelectMany并将这些结果与原始值一起投影到新类型中,然后根据它进行过滤。 / p>

myObservable.SelectMany(async item => new 
  {
    ShouldInclude = (await Rank(item)) > 5,
    Item = item
  })
  .Where(o => o.ShouldInclude)
  .Select(o => o.Item);

我认为这是非常难以理解的,但我觉得必须有一个更清洁的方式。

2 个答案:

答案 0 :(得分:13)

  

我认为这非常难以理解

是的,但您可以通过将其封装到辅助方法中来解决这个问题。如果您将其称为Where,您将获得所需的语法:

public static IObservable<T> Where<T>(
    this IObservable<T> source, Func<T, Task<bool>> predicate)
{
    return source.SelectMany(async item => new 
        {
            ShouldInclude = await predicate(item),
            Item = item
        })
        .Where(x => x.ShouldInclude)
        .Select(x => x.Item);
}

答案 1 :(得分:2)

或者,您可以使用以下内容:

public static IObservable<T> Where<T>(
    this IObservable<T> source, Func<T, Task<bool>> predicate)
{
    return source.SelectMany(item => 
        predicate(item).ToObservable()
            .Select(include => include ? Observable.Return(item) : Observable.Empty<T>())
        );
}

基本上Where如何运作,如果你用SelectMany来定义它:

public static IObservable<T> Where<T>(
    this IObservable<T> source, Func<T, bool> predicate)
{
    return source.SelectMany(item => predicate(item) ? Observable.Return(item) : Observable.Empty<T>());
}

实际上,@ svick的答案有更少的关闭。 :)