Подтвердить что ты не робот

Наблюдаемый. Где с асинхронным предикатом

Есть ли удобный способ использовать асинхронную функцию как предикат оператора Where на наблюдаемом?

Например, если у меня есть хорошая аккуратная, но возможно долгосрочная функция, определенная следующим образом:

Task<int> Rank(object item);

Есть ли трюк для передачи его на Where и поддержания асинхронного выполнения? Как в:

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

В прошлом, когда мне это нужно, я прибегал к использованию SelectMany и проектировал эти результаты в новый тип вместе с исходным значением, а затем выполнял фильтрацию на основе этого.

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

Я думаю, что это ужасно нечитаемо, хотя я чувствую, что должен быть более чистый способ.

4b9b3361

Ответ 1

Я думаю, что ужасно нечитаемый

Да, но вы можете исправить это, инкапсулируя его в вспомогательный метод. Если вы назовете его 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);
}

Ответ 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 имеет меньше замыканий.:)