2016-09-28 9 views
2

は、私はこのような複数のタスクを作成するforeachループを持っている:作成したオブジェクトをタスクにどのように廃棄するのですか?

[編集:CreateDisposableAsyncを返しタスク[IDisposableを]]

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

と私は、これらのタスクのすべてに待っていて、すべての例外をキャッチし、後で:

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

しかしCreateDisposableAsync()の呼び出しが、私はタスクのいずれかで例外があったかどうかを配置することにしたいIDisposableをし、返します。これどうやってするの?

[編集:それ自体が例外を投げたので、元のコードと間違って何もなかった場合CreateDisposableAsync()関数は、その作成されたオブジェクトを廃棄していることが判明した。]

+0

「タスク」の種類は何ですか?あなたは処分する必要がありますか? https://blogs.msdn.microsoft.com/pfxteam/2012/03/25/do-i-need-to-dispose-of-tasks/ –

+0

最も簡単な方法は、 'CreateDisposableAsync'が独自のリソースをクリーンアップすることです処分する必要のあるオブジェクトを処分する責任があります。 – Igor

+0

@ LasseV.Karlsen戻り値の型はTask

答えて

2

Q:あなたは、呼び出し元のコード

Aでの結果で何かを(あるいはやりたい)んん、結果を配置する例外:いいえ私はこれを行う最も簡単な方法は、それを返す前にCreateDisposableAsync方法は、独自のリソースをクリーンアップすることですし、を返さない

Task<IDisposable>の代わりにを入力します。オペレーションに示されている既存の呼び出しコードは変更する必要はありません。

// 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 
    } 
} 
1

完了意志に走ったタスクのみ処理できるオブジェクトが返されました。完了したタスクにリストをフィルタリングし、結果を選択するだけです。

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; 
    } 
} 
+0

@Servy良い点、修正済み。 –

+1

OPが 'catch(AggregateException)'の後でオブジェクトが破棄される前に追加作業が必要だったかどうかはわかりませんでした。 Servletが述べたように、2つのtryブロックをマージし、 'try/catch/finally'を使用することができます。 –

+0

@Servyいいえ、 'AggregateException'がtryブロックからあなたを追い出すので、正常に完了した結果で何かをしたいのであれば、' catch(AggregateException) 'ブロックの後にする必要があります。編集:しかし、[OPのコメントを読んだ後に](http://stackoverflow.com/questions/39750215/how-to-dispose-of-an-object-that-it-created-in-a-task/39750333? noredirect = 1#comment66797413_39750215)私は彼が余分な仕事をしていないと思う。だからそれは合併することができた。私は私の答えを更新します。 –

1

別の解決策のように思えるので、私はここにこれを掲示しています:usingステートメントを作成IDisposableインターを配置することができ、そのよう

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

、その後

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

+0

もし私が間違っていても 'CreateDisposableAsync'が例外をスローするならば、それを正してください。正式に決して' using'ブロックに入ることはないので、まだ処分されません。これは、同じ問題が残っていることを意味し、コールシグネチャを変更できない場合は、スコットの答えが最善の選択肢になります。 – Igor

+1

@Igor例外をスローすると、処分できる「IDisposable」オブジェクトが決して存在しないので、外部の呼び出し元の観点からは何も実行されません(内部呼び出し可能なリソースを返すメソッドリソースの作成後にいつでも例外がスローされる可能性があるが、返される前にtry/catchおよびリソースを処分する必要があります)。 – Servy

+0

@Servy - このメソッドが使い捨てインスタンスメンバーを作成すると仮定して、 'CreateDisposableAsync'に例外がスローされる場所に依存しませんか?私は、例外が発生した場合でも常にIDIsposableの結果を処分しなければならないとOPが述べているという事実に基づいて、その可能な仮定を行った。だから、 'CreateDisposableAsync'が例外があればクリーンアップすると仮定すると、問題はありません。 – Igor

関連する問題