2020 年 3 月更新
.NET Core 3.0(和3.1)现已发布,完全支持异步流。这Microsoft.Bcl.AsyncInterfaces https://www.nuget.org/packages/Microsoft.Bcl.AsyncInterfaces/向 .NET Standard 2.0 和 .NET Framework 4.6.1+ 添加了对它们的支持,尽管出于理智原因应使用 4.7.2。正如文档上.NET 标准实现支持说明 https://learn.microsoft.com/en-us/dotnet/standard/net-standard#net-implementation-support
虽然 NuGet 认为 .NET Framework 4.6.1 支持 .NET Standard 1.5 到 2.0,但使用为 .NET Framework 4.6.1 项目中的这些版本构建的 .NET Standard 库存在一些问题。
对于需要使用此类库的 .NET Framework 项目,我们建议您将项目升级到目标 .NET Framework 4.7.2 或更高版本。
原答案
If you 检查源代码 https://github.com/StackExchange/Dapper/blob/master/Dapper/SqlMapper.Async.cs#L433,你会发现你的怀疑几乎是正确的。什么时候buffered
是假的,QueryAsync
将流式传输同步地.
if (command.Buffered)
{
var buffer = new List<T>();
var convertToType = Nullable.GetUnderlyingType(effectiveType) ?? effectiveType;
while (await reader.ReadAsync(cancel).ConfigureAwait(false))
{
object val = func(reader);
if (val == null || val is T)
{
buffer.Add((T)val);
}
else
{
buffer.Add((T)Convert.ChangeType(val, convertToType, CultureInfo.InvariantCulture));
}
}
while (await reader.NextResultAsync(cancel).ConfigureAwait(false)) { /* ignore subsequent result sets */ }
command.OnCompleted();
return buffer;
}
else
{
// can't use ReadAsync / cancellation; but this will have to do
wasClosed = false; // don't close if handing back an open reader; rely on the command-behavior
var deferred = ExecuteReaderSync<T>(reader, func, command.Parameters);
reader = null; // to prevent it being disposed before the caller gets to see it
return deferred;
}
正如评论所解释的,不可能使用ReadAsync
当返回类型预计为 IEnumerable 时。这就是为什么必须引入 C# 8 的异步枚举的原因。
ExecuteReaderSync 的代码是:
private static IEnumerable<T> ExecuteReaderSync<T>(IDataReader reader, Func<IDataReader, object> func, object parameters)
{
using (reader)
{
while (reader.Read())
{
yield return (T)func(reader);
}
while (reader.NextResult()) { /* ignore subsequent result sets */ }
(parameters as IParameterCallbacks)?.OnCompleted();
}
}
It uses Read
代替ReadAsync
.
C#8 异步流将允许重写它以返回IAsyncEnumerable
。仅仅更改语言版本并不能解决问题。
鉴于异步流的当前文档,这可能如下所示:
private static async IAsyncEnumerable<T> ExecuteReaderASync<T>(IDataReader reader, Func<IDataReader, object> func, object parameters)
{
using (reader)
{
while (await reader.ReadAsync())
{
yield return (T)func(reader);
}
while (await reader.NextResultAsync(cancel).ConfigureAwait(false)) { /* ignore subsequent result sets */ }
command.OnCompleted();
(parameters as IParameterCallbacks)?.OnCompleted();
}
}
Buuuuuut异步流是只能在 .NET Core 上运行的功能之一,并且可能尚未实现。当我尝试在 Sharplab.io 上写一个时,Kaboom。[connection lost, reconnecting…]