I’m trying to do the equivalent of the dollowing C# 5 pseudocode:-
async Task<int> CallAndTranslate()
{
try
{
return await client.CallAsync();
} catch(FaultException ex) {
if (ex.FaultCode ...)
throw new Exception("translated");
}
}
Given an arbitrary Task which does not return a result, translating exceptions when backporting from C# 5 is easy using the technique supplied by @Drew Marsh
This technique doesn’t generalize trivially to Task<T> as any overload of Task.ContinueWith I can see returns a bald Task, not a Task<T>.
Is there a way to achieve this using the TPL APIs without having to resort to:
- wrapping it in another
Task<T> - causing the exception to go through the machinations of getting thrown and caught through the exception handling mechanisms
- ADDED After intial answer…. should leave stack trace alone if exception is not to be translated
Here’s my naive placeholder implementation:
public class TranslatingExceptions
{
Task<int> ApiAsync()
{
return Task<int>.Factory.StartNew( () => {
throw new Exception( "Argument Null" ); } );
}
public Task<int> WrapsApiAsync()
{
return ApiAsync().TranslateExceptions(x=>{
if (x.Message == "Argument Null" )
throw new ArgumentNullException();
});
}
[Fact]
public void Works()
{
var exception = Record.Exception( () =>
WrapsApiAsync().Wait() );
Assert.IsType<ArgumentNullException>( exception.InnerException );
}
}
The following Task<T> extension implements my placeholder implementation:
static class TaskExtensions
{
public static Task<T> TranslateExceptions<T>( this Task<T> task, Action<Exception> translator )
{
// TODO REPLACE NAIVE IMPLEMENTATION HERE
return Task<T>.Factory.StartNew( () =>
{
try
{
return task.Result;
}
catch ( AggregateException exception )
{
translator( exception.InnerException );
throw;
}
} );
}
}
You can imitate
awaitin .NET 4.0 using iterators (yield), but it’s not pretty.Without a state machine, you’re missing the whole point of
awaitwhich is to return control to the caller until the work is complete and only then continue execution.Um, maybe I’ve missed the point! If you just want to use a
ContinueWith<T>it’s just a slight tweak to the code from Drew Marsh:UPDATE: sample using TaskCompletionSource