我有一个foreach循环,可以创建多个这样的任务:
[edit:CreateDisposableAsync返回任务[IDisposable]]
foreach(...)
{
tasks.Add(CreateDisposableAsync());
}
以后我等待所有这些任务,并抓住任何例外:
try
{
await Task.WhenAll(tasks);
}
catch (AggregateException)
{
// handle exceptions
}
但是对CreateDisposableAsync()的调用会返回一个IDisposable,无论是否在任何任务中都存在异常,我都要处理它。我怎么能这样做?
[编辑:事实证明,如果自己引发异常,CreateDisposableAsync()函数正在处理其创建的对象,因此原始代码没有任何问题。]
答案 0 :(得分:2)
只有运行完成的任务才会返回可以处理的对象。只需将列表过滤到已完成的任务,然后选择结果。
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;
}
}
答案 1 :(得分:2)
来自评论
问:除了处理结果外,您是否(或想要)在调用代码中执行任何其他结果
答:不,我不
最简单的方法是让/*
方法在返回之前清理自己的资源并返回CreateDisposableAsync
而不是Task
。 OP中显示的现有调用代码不必更改。
Task<IDisposable>
答案 2 :(得分:1)
我在这里张贴这个,因为它似乎是另一种解决方案:
private static async Task CallCreateDisposableAsync()
{
using (await CreateDisposableAsync()) { }
}
然后
foreach(...)
{
tasks.Add(CallCreateDisposableAsync);
}
这样,using语句可以处理创建的IDisposable。