我在MS reference查看DbDataReader(也是DbCommand)的代码,无法弄清楚ReadAsync()方法中的异步。
virtual public Task<bool> ReadAsync(CancellationToken cancellationToken) {
if (cancellationToken.IsCancellationRequested) {
return ADP.CreatedTaskWithCancellation<bool>();
}
else {
try {
return Read() ? ADP.TrueTask : ADP.FalseTask;
}
catch (Exception e) {
return ADP.CreatedTaskWithException<bool>(e);
}
}
}
ReadAsync方法只调用Read方法并返回一个完整的任务。 这不会像调用Read一样阻塞调用线程吗?
我注意到DbCommand ExecuteReaderAsync和其他方法中的模式相同。他们只需调用同步版本并返回已完成的任务。
我在这里缺少什么?
更新:我没有错过任何东西,因为@PeterBons很好地解释了(也在the documentation)。我仍然不喜欢它,但那是我的问题。
答案 0 :(得分:4)
您正在查看抽象类中的虚方法。如果您希望(未来)实现能够执行一些真正的异步工作,则必须定义允许该方法签名的方法签名。所以它应该返回Task
或Task<T>
。请记住,只使用一个任务不会使任何异步,它使它等待。
在此示例虚拟方法中使用Task<bool>
返回类型是为了便于从DbDataReader派生的其他类在其ReadAsync实现中提供真正的异步行为。
例如,真正的异步实现可以执行类似
的操作class TrueAsyncReader : DbDataReader
{
...
public override async Task<bool> ReadAsync(CancellationToken cancellationToken)
{
...
return await ReadFromDbAsync();
}
}
如您所见,您现在可以拥有异步和非异步实现,而无需更改方法签名。
由于您可以轻松地从异步方法调用同步代码,因此这是可行的方法。从同步方法调用异步代码是一件好事。
对于需要返回任务的非异步实现,您可以返回Task.FromResult<T>
或Task.CompletedTask
之类的内容。这不会阻止。
另见await Task.CompletedTask for what?
总结一下:默认实现不会执行任何异步,但派生类可以不必更改方法签名。