如何处置它在任务中创建的对象?

时间:2016-09-28 14:19:22

标签: c#

我有一个foreach循环,可以创建多个这样的任务:

[edit:CreateDisposableAsync返回任务[IDisposable]]

foreach(...)
{
   tasks.Add(CreateDisposableAsync());
}

以后我等待所有这些任务,并抓住任何例外:

try
{
   await Task.WhenAll(tasks);
}
catch (AggregateException)
{
   // handle exceptions
}

但是对CreateDisposableAsync()的调用会返回一个IDisposable,无论是否在任何任务中都存在异常,我都要处理它。我怎么能这样做?

[编辑:事实证明,如果自己引发异常,CreateDisposableAsync()函数正在处理其创建的对象,因此原始代码没有任何问题。]

3 个答案:

答案 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。