简体   繁体   English

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

[英]How to dispose of an object that it created in a task?

I have a foreach loop that creates multiple tasks like this: 我有一个foreach循环,可以创建多个这样的任务:

[edit: CreateDisposableAsync returns a Task[IDisposable]] [编辑:CreateDisposableAsync返回任务[IDisposable]]

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

and later I await on all of these tasks, and catch any exceptions: 后来我等待所有这些任务,并捕获任何异常:

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

but the call to CreateDisposableAsync() returns an IDisposable, which I want to be disposed whether or not there was an exception in any of the tasks. 但是对CreateDisposableAsync()的调用会返回一个IDisposable,无论是否在任何任务中都存在异常,我都要处理它。 How can I do this? 我怎样才能做到这一点?

[Edit: It turns out that the CreateDisposableAsync() function was disposing of its created object if itself threw an exception, so there was nothing wrong with the original code.] [编辑:事实证明,CreateDisposableAsync()函数在它自己引发异常的情况下处理了它的创建对象,因此原始代码没有任何问题。

From the comments 从评论

Q: with the exception of disposing the result do you do (or want to do) anything else with the result in the calling code 问:除了处理结果之外,您是否(或想要)在调用代码中执行任何其他结果

A: No I do not 答:不,我没有

The easiest way to do this is to have the CreateDisposableAsync method clean up its own resources before it returns and return Task instead of Task<IDisposable> . 最简单的方法是让CreateDisposableAsync方法在返回之前清理自己的资源并返回Task而不是Task<IDisposable> The existing calling code shown in the OP would not have to change. 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
   }
}

Only tasks that ran to completion will have returned objects that could be disposed. 只有运行完成的任务才会返回可以处理的对象。 Just filter the list to the tasks that completed then select the results. 只需将列表过滤到已完成的任务,然后选择结果。

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.
        }
    }
}

Or if you do not plan on doing any other work after the WaitAll 或者,如果您不打算在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.
        }
    }
}

Tasks that threw errors don't return objects, there is no way to dispose of them outside of CreateDisposableAsync() and it would be that function's responsibility to dispose of them if there was any kind of error. 抛出错误的任务不返回对象,没有办法在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;
    }
}

I'm posting this here because it seems like an alternative solution: 我在这里发布这个,因为它似乎是一个替代解决方案:

    private static async Task CallCreateDisposableAsync()
    {
         using (await CreateDisposableAsync()) { }
    }

and then 然后

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

that way the using statement can dispose the created IDisposable. 这样,using语句可以处理创建的IDisposable。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM