После прочтения этой статьи о чрезмерном await
использовании я решил убрать ожидание, где это возможно. Это привело к проблеме с моими службами данных по двум причинам:
- Все методы, которые получают коллекцию, возвращают
Task<IEnumerable<T>>
по соглашению - EF не обеспечивает
ToEnumerableAsync
.
Теперь, когда я удаляю await
, компилятор больше не разворачивает Task
объекты, и у меня остается ошибка компиляции, которая говорит, что Task<List<T>>
нельзя преобразовать в Task<IEnumerable<T>>
.
Поэтому я решил создать свой собственный ToEnumerableAsnyc
. Версия "PoC" выглядела так:
public static IEnumerable<T> ToEnumerableAsync<T>(this IQueryable<T> source)
=> (await source.ToListAsync()).AsEnumerable();
Однако это только обертывает лишние await
и не удаляет их, то есть все еще есть мой await
и тот, который использовался внутренне из ToListAsync
,Насколько я понимаю из приведенной выше статьи, это создает ненужные накладные расходы. Это не важно, но накладные расходы, тем не менее. Пожалуйста, исправьте меня, если я ошибаюсь:)
Поэтому я решил выяснить, как разработчики Microsoft собирались реализовать ToListAsync
в ASP.NET Core 2.2 , и мне удалось создать свой собственныйреализация ToEnumerableAsync
, которая не использует await
в зависимости от их решения. Вот как это выглядит:
public static Task<IEnumerable<T>> ToEnumerableAsync<T>(this IQueryable<T> queryable)
{
var asyncEnum = AsAsyncEnumerable(queryable);
var list = new List<T>();
return asyncEnum.Aggregate(
(IEnumerable<T>)list,
(list, x) =>
{
((List<T>)list).Add(x);
return list;
});
}
private static IAsyncEnumerable<T> AsAsyncEnumerable<T>(this IQueryable<T> queryable)
{
if (queryable is IAsyncEnumerable<T> asyncEnumerable)
{
return asyncEnumerable;
}
throw new InvalidOperationException(
$"Cannot cast \"IQueryable\" to \"IAsyncEnumerable\". Type: \"{typeof(T).FullName}\"");
}
И, наконец, на мой вопрос: что может пойти не так с приведением от IQueryable<T>
к IAsyncEnumerable<T>
, которое разработчики явно указали InvalidOperationExeption
? Как и почему IQueryable<T>
не может привести к IAsyncEnumerable<T>
?
Исходный файл EF: QueriableExtensions.cs .