如何处置在任务中创建的对象
本文关键字:创建 对象 任务 何处置 | 更新日期: 2023-09-27 18:09:30
我有一个foreach循环,它创建了多个任务,像这样:
[edit: CreateDisposableAsync return a Task[IDisposable]]
foreach(...)
{
tasks.Add(CreateDisposableAsync());
}
,然后等待所有这些任务,并捕获任何异常:
try
{
await Task.WhenAll(tasks);
}
catch (AggregateException)
{
// handle exceptions
}
但是对CreateDisposableAsync()的调用返回一个IDisposable,无论在任何任务中是否存在异常,我都希望处置它。我该怎么做呢?
[编辑:事实证明,CreateDisposableAsync()函数是处置其创建的对象,如果本身抛出一个异常,所以没有任何错误与原始代码]
从注释
Q:在调用代码
中,除了处理结果之外,你还对结果做(或想做)任何其他事情吗?A:不,我没有
最简单的方法是让CreateDisposableAsync
方法在返回之前清理自己的资源,并返回Task
而不是Task<IDisposable>
。OP中显示的现有调用代码无需更改。
// change the signature
async Task CreateDisposableAsync(){
// use using blocks for anything that needs to be disposed
// try/finally is also acceptable
using(var someDisposableInstance = new SomethingDisposable()){
// implementation
}
}
只有运行到完成的任务才会返回可以被处置的对象。只需将列表筛选到已完成的任务,然后选择结果。
try
{
try
{
await Task.WhenAll(tasks);
}
catch (AggregateException)
{
// handle exceptions
}
//do other stuff with the returned task objects.
}
finally
{
foreach(var item in tasks.Where(x=>x.Status == TaskStatus.RanToCompletion).Select(x=>x.Result))
{
//We use a try block so if Dispose throws it does not break the loop.
try
{
item.Dispose();
}
catch(Exception ex)
{
//Log any exception on dispose.
}
}
}
或者如果您不打算在WaitAll
之后做任何其他工作
try
{
await Task.WhenAll(tasks);
}
catch (AggregateException)
{
// handle exceptions
}
finally
{
foreach(var item in tasks.Where(x=>x.Status == TaskStatus.RanToCompletion).Select(x=>x.Result))
{
//We use a try block so if Dispose throws it does not break the loop.
try
{
item.Dispose();
}
catch(Exception ex)
{
//Log any exception on dispose.
}
}
}
抛出错误的任务不返回对象,没有办法在CreateDisposableAsync()
之外处理它们,如果有任何类型的错误,则由该函数负责处理它们。
public async Task<MyDisposeableClass> CreateDisposableAsync()
{
MyDisposeableClass myDisposeableClass = null;
try
{
myDisposeableClass = new MyDisposeableClass();
//...
return myDisposeableClass;
}
catch
{
//dispose of the class if the instance was created.
if(myDisposeableClass != null)
myDisposeableClass.Dispose();
//let the execption bubble up.
throw;
}
}
我把这个贴在这里,因为它似乎是一个替代的解决方案:
private static async Task CallCreateDisposableAsync()
{
using (await CreateDisposableAsync()) { }
}
和
foreach(...)
{
tasks.Add(CallCreateDisposableAsync);
}