使用List模拟数据库异步访问时遇IAsyncQueryProvider未实现,求通用解
解决List转IQueryable后异步LINQ操作的"IAsyncQueryProvider未实现"问题
问题场景
使用List<T>.AsQueryable()转换得到的IQueryable<T>执行异步LINQ方法(如CountAsync、ToListAsync)时,会触发错误:
源'IQueryable'的提供程序未实现'IAsyncQueryProvider'
这是因为默认的EnumerableQuery<T>并未实现异步查询提供器接口,无法支持EF Core风格的异步LINQ扩展方法。
通用解决方案(支持值类型+引用类型)
我们可以自行实现一个通用的异步查询提供器和包装类,无需依赖EF内存数据库或第三方库。以下是完整实现:
1. 异步查询提供器实现
using System.Linq; using System.Linq.Expressions; using System.Threading; using System.Threading.Tasks; public class AsyncQueryProvider<TEntity> : IAsyncQueryProvider { private readonly IQueryProvider _innerProvider; public AsyncQueryProvider(IQueryProvider innerProvider) { _innerProvider = innerProvider; } public IQueryable CreateQuery(Expression expression) { return new AsyncQueryableWrapper<TEntity>(expression, this); } public IQueryable<TElement> CreateQuery<TElement>(Expression expression) { return new AsyncQueryableWrapper<TElement>(expression, this); } public object Execute(Expression expression) { return _innerProvider.Execute(expression); } public TResult Execute<TResult>(Expression expression) { return _innerProvider.Execute<TResult>(expression); } public Task<object> ExecuteAsync(Expression expression, CancellationToken cancellationToken) { return Task.FromResult(Execute(expression)); } public Task<TResult> ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken) { return Task.FromResult(Execute<TResult>(expression)); } }
2. 异步Queryable包装类
public class AsyncQueryableWrapper<T> : IQueryable<T>, IAsyncEnumerable<T> { private readonly IQueryable<T> _innerQuery; public AsyncQueryableWrapper(Expression expression, IAsyncQueryProvider provider) { _innerQuery = new EnumerableQuery<T>(expression); Provider = provider; Expression = expression; } public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default) { return new AsyncEnumeratorWrapper<T>(_innerQuery.GetEnumerator()); } public IEnumerator<T> GetEnumerator() { return _innerQuery.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public Type ElementType => _innerQuery.ElementType; public Expression Expression { get; } public IQueryProvider Provider { get; } } public class AsyncEnumeratorWrapper<T> : IAsyncEnumerator<T> { private readonly IEnumerator<T> _innerEnumerator; public AsyncEnumeratorWrapper(IEnumerator<T> innerEnumerator) { _innerEnumerator = innerEnumerator; } public ValueTask DisposeAsync() { _innerEnumerator.Dispose(); return ValueTask.CompletedTask; } public ValueTask<bool> MoveNextAsync() { return ValueTask.FromResult(_innerEnumerator.MoveNext()); } public T Current => _innerEnumerator.Current; }
3. 扩展方法:AsAsyncQueryable
public static class AsyncQueryableExtensions { public static IQueryable<T> AsAsyncQueryable<T>(this IEnumerable<T> source) { var queryable = source.AsQueryable(); return new AsyncQueryableWrapper<T>(queryable.Expression, new AsyncQueryProvider<T>(queryable.Provider)); } }
修改后的测试代码
[Fact] public async Task TestAsyncFromList() { List<int> items = new List<int>() { 1,2,3,4,5,6,7,8,9,10}; var queryable = items.AsAsyncQueryable(); // 使用自定义扩展方法 var totalSync = queryable.Count(); var totalAsync = await queryable.CountAsync(); Assert.True(totalSync == totalAsync); }
说明
- 该实现通过包装原有的同步查询提供器,将异步操作转换为同步执行后包装成Task,完全兼容EF Core的异步LINQ扩展方法。
- 支持所有值类型(如int、DateTime)和引用类型,无需针对不同类型做特殊处理。
- 避免了第三方库的限制,也无需依赖EF内存数据库,适合单元测试中模拟异步数据访问场景。
内容的提问来源于stack exchange,提问作者Ewen Stewart
相关产品推荐
相关产品推荐

