Наблюдаемый. Где с асинхронным предикатом
Есть ли удобный способ использовать асинхронную функцию как предикат оператора 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);
Я думаю, что это ужасно нечитаемо, хотя я чувствую, что должен быть более чистый способ.
Ответы
Ответ 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 имеет меньше замыканий.:)