C# 可观察。其中使用异步谓词

C# 可观察。其中使用异步谓词,c#,async-await,system.reactive,C#,Async Await,System.reactive,有没有一种方便的方法可以使用异步函数作为可观察对象上Where运算符的谓词 例如,如果我有一个整洁但可能长期运行的函数,定义如下: Task<int> Rank(object item); public static IObservable<T> Where<T>( this IObservable<T> source, Func<T, Task<bool>> predicate) { return sou

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

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

Task<int> Rank(object item);
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>())
        );
}
在过去,当我需要这样做时,我会使用SelectMany并将这些结果与原始值一起投影到一个新类型中,然后在此基础上进行过滤

myObservable.SelectMany(async item => new 
  {
    ShouldInclude = (await Rank(item)) > 5,
    Item = item
  })
  .Where(o => o.ShouldInclude)
  .Select(o => o.Item);
我觉得这太难理解了,我觉得一定有更干净的方法

我觉得那太难读了

是的,但是您可以通过将其封装到helper方法中来解决这个问题。如果将其命名为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);
}

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

Task<int> Rank(object item);
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>())
        );
}

事实上,@svick的答案有更少的闭包

您希望项目在排名完成时进入结果流,还是它们会保持其原始顺序?我对两者都感兴趣,但假设在这种情况下,顺序不受关注。+1。这可能是最简单的解决方案,实际上很好。我真不敢相信我以前从未想到过。为什么要用Map来代替更常见的名称,至少在C选择中是这样?Map是标准的函数编程术语。Select是原始LINQ到SQL实现遗留下来的术语。据我所知,Map不存在于Rx的.NET版本中,但存在于RxJS中。基本上,我只是习惯于编写映射而不是选择。实际上,在System.Reactive.Observable.Alias命名空间中。啊,在这种情况下,我可能会在.NET中开始使用它,以与世界其他地方保持一致