Bra*_*don 4 c# task async-await dapper
为什么调用.Result此方法会导致TaskCanceledException:
public Task<IEnumerable<object>> GetAsync()
{
using (var conn = new SqlConnection("connectionString"))
{
return conn.QueryAsync<object>("select * from objects");
}
}
Run Code Online (Sandbox Code Playgroud)
但是调用.Result这个方法有效:
public async Task<IEnumerable<object>> GetAsync()
{
using (var conn = new SqlConnection("connectionString"))
{
return await conn.QueryAsync<object>("select * from objects");
}
}
Run Code Online (Sandbox Code Playgroud)
区别在于async\await第二种方法中使用的是关键字.
The reason the first method throws an exception is because the SqlConnection object is going out of scope when the Task is returned from the method.
The reason the second method works is because the async & await keywords simulate a closure due to the compiler wrapping the method in a state-machine-like struct behind the scenes. This ends up keeping the SqlConnection in scope. I won't go much further than that because the details are a bit complex and vary based on the compiler.
To make it possible to return a Task without the async/await keywords you'd need to pass in the SqlConnection so it remains in scope upon returning the Task:
public Task<IEnumerable<object>> GetAsync(SqlConnection conn)
{
return conn.QueryAsync<object>("select * from objects");
}
Run Code Online (Sandbox Code Playgroud)
Why it has to do with scope and closures:
SqlConnection在语句中实例化using将其范围限制为using块。因此,当第一个方法离开using块并返回任务时,任务SqlConnection就会超出范围并在任务完成之前被释放。在第二种方法中,关键字将导致编译器在后台async/await创建 a ,并将异步方法的局部变量存储为该结构中的字段,以便在任务完成时可以在回调(await 下面的代码)中使用它们。struct这类似于闭包在幕后的实现方式。