如果在 using 语句中进行异步调用,并且调用的结果是异步处理的(即发生这种情况的方法是异步的,并且在结果加载和处理之前返回),则 using 语句是否可以退出范围? 换句话说,做这样的事情是否安全:
async void LoadAndProcessStuff()
{
using(var ctx = CreateDBContext()){
someResource.LoadStuffsAsync().ForEachAsync(stuff => ctx.Stuffs.Add(stuff));
}
}
或
async void LoadAndProcessStuff2()
{
using(var ctx = CreateDBContext()){
ctx.Stuffs.Select(stuff => someResource.LoadMoreStuffsAsync(stuff))
.ForEachAsync(stuff => ctx.Stuffs2.AddRange(stuff.Result));
}
}
或者 ctx 是否可以在调用 ForEachAsync 时被 Dispose 并导致异常?
最佳答案
在异步方法中,“using”关键字应该是安全的。编译器只是将其重写为“finally”表达式,其工作方式与异步方法中的所有其他异常处理类似。请注意,Dispose() 不应阻塞或长时间运行,它应该只释放资源 - 除非您想瘫痪您的服务器。
这是安全案例的简单测试案例:
using System;
using System.Threading.Tasks;
namespace so {
sealed class Garbage : IDisposable {
public void Dispose() {
Console.WriteLine("Disposing Garbage");
}
}
// Garbage is safely Disposed() only after delay is done
class Program {
public static async Task Main() {
using (Garbage g = new Garbage()) {
Console.WriteLine("Delay Starting");
await Task.Delay(1000);
Console.WriteLine("Delay Finished");
}
}
}
}
但是,如果您有一个返回任务而不是等待任务的非异步方法,则可能不安全。这是因为同步方法仅被调用一次。编译器没有生成协程或状态机,因此必须立即调用 Dispose() - 可能在任务仍在运行时调用。
public Task DoWorkAsync()
{
using (var service = new Service())
{
var arg1 = ComputeArg();
var arg2 = ComputeArg();
// NOT SAFE - service will be disposed
// There is a high-probability that this idiom results
// in an ObjectDisposedException
return service.AwaitableMethodAsync(arg1, arg2);
}
}
引用:http://www.thebillwagner.com/Blog/Item/2017-05-03-ThecuriouscaseofasyncawaitandIDisposable
关于c# - 没有await的using语句中的async,这安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48126982/