You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 09:30:57