2015-05-14 12 views
5

Ich habe etwas Code, den ich von .NET 4.5 der schönen async und await Schlüsselwörter auf .NET 4.0 herabstufen. Ich benutze ContinueWith, um eine Fortsetzung ähnlich der Art und Weise await funktioniert zu erstellen.So fangen Sie eine OperationCanceledException bei der Verwendung von ContinueWith

Grundsätzlich meine alten Code war:

var tokenSource = newCancellationTokenSource(); 
var myTask = Task.Run(() => 
{ 
    return MyStaticClass.DoStuff(tokenSource.Token); 
}, tokenSource.Token); 
try 
{ 
    var result = await myTask; 
    DoStuffWith(result); 
} 
catch (OperationCanceledException) 
{ 
    // Cancel gracefully. 
} 

(Wie man erwarten könnte, MyStaticClass.DoStuff(token)token.ThrowIfCancellationRequested() regelmäßig aufruft.)

Mein neuer Code wie folgt aussieht:

var tokenSource = new CancellationTokenSource(); 
try 
{ 
    Task.Factory.StartNew(() => 
    { 
     return MyStaticClass.DoStuff(tokenSource.Token); 
    }, tokenSource.Token) 
    .ContinueWith(task => 
    { 
     var param = new object[1]; 
     param[0] = task.Result; 
     // I need to use Invoke here because "DoStuffWith()" does UI stuff. 
     Invoke(new MyDelegate(DoStuffWith, param)); 
    }); 
} 
catch (OperationCanceledException) 
{ 
    // Cancel gracefully. 
} 

jedoch Die OperationCanceledException wird nie gefangen. Was ist los? Wo setze ich meinen Try/Catch-Block?

+5

Beachten Sie, dass Sie warten mit .NET 4.0 verwenden, können mit https://www.nuget.org/packages/Microsoft.Bcl.Async/ –

Antwort

6

Die Stornierung wird anders als bei anderen Ausnahmen behandelt. Grundsätzlich können Sie dieses Muster verwenden:

Task.Factory.StartNew(() => 
{ 
    // The task 
}, tokenSource.Token) 
.ContinueWith(task => 
{ 
    // The normal stuff 
}, TaskContinuationOptions.OnlyOnRanToCompletion) 
.ContinueWith(task => 
{ 
    // Handle cancellation 
}, TaskContinuationOptions.OnlyOnCanceled) 
.ContinueWith(task => 
{ 
    // Handle other exceptions 
}, TaskContinuationOptions.OnlyOnFaulted); 

Oder die Alternative ein:

Task.Factory.StartNew(() => 
{ 
    // The task 
}, tokenSource.Token) 
.ContinueWith(task => 
{ 
    switch (task.Status) 
    { 
    case TaskStatus.RanToCompletion: 
     // The normal stuff 
     break; 
    case TaskStatus.Canceled: 
     // Handle cancellation 
     break; 
    case TaskStatus.Faulted: 
     // Handle other exceptions 
     break; 
    } 
}); 

In Ihrem Fall sind Sie nicht etwas zu fangen, weil:

  • Task.Factory.StartNew kehrt sofort und immer gelingt es.
  • Ihre Fortsetzung läuft immer
  • Zugriff task.Result eine AggregateException wirft, da die Aufgabe
  • Die Ausnahme abgebrochen wird von etwas nicht behandelt wird, da es von einem Thread-Pool-Thread geworfen wird. Hoppla. Was passiert als nächstes depends on the framework version:

    • In .NET < 4.5, wird der Prozess, sobald die fehlerhafte Aufgabe beendet ist abgeschlossen, da Sie eine unbeobachtete Ausnahme haben.
    • In .NET> = 4.5 wird die Ausnahme automatisch gelöscht.
Verwandte Themen