Small Task quiz knowledge
The task and the await /async never ceases to amaze me. That because there is so much under covers( see https://channel9.msdn.com/Events/TechDays/Techdays-2014-the-Netherlands/Async-programming-deep-dive )
Let’s say that we have this code that awaits and throws ( or not ) an exception:
static async Task<bool> test(int delaySeconds, Exception throwEx) { Console.WriteLine($"enter {delaySeconds} "); await Task.Delay(delaySeconds * 1000); Console.WriteLine($"finish waiting {delaySeconds} and throw Exception: {throwEx.Message}"); if (throwEx != null) { throw throwEx;//never do this in production } return true; }
First problem: Error order
What this code will produce as output for the line Console.WriteLine(“err ” + ex.GetType().Name); ?
Console.WriteLine("start"); var t10Ex = test(delaySeconds: 10, throwEx: new ArgumentException("problem with argument")); var t19Ex = test(delaySeconds: 19, throwEx: new DllNotFoundException("not found dll")); var t100NotEx = test(delaySeconds: 100, throwEx: null); try { await Task.WhenAll(new Task[] { t19Ex, t10Ex, t100NotEx }); } catch (Exception ex) { Console.WriteLine("err " + ex.GetType().Name); } finally { Console.WriteLine("in finally"); } Console.WriteLine("waiting in main"); await Task.Delay(100 * 1000); Console.WriteLine("finish");
Answer: err DllNotFoundException
. That is because the await it produce error for the first item in the array , not for the first item in chronological order. More, it will wait for all tasks to finish.
Second problem: Grab all errors
How do you modify the above code to grab all errors ?
Answer: By introducing a new variable, tAll . Attention: the exception is the same ( dllNotFound), however, the whole AggregateException is in tAll.Exception
Task tAll=null; try { tAll = Task.WhenAll(new Task[] { t19Ex, t10Ex, t100NotEx }); await tAll; } catch (Exception ex) { Console.WriteLine("err " + ex.GetType().Name); Console.WriteLine(" all exception here:" + tAll.Exception); } finally { Console.WriteLine("in finally"); }
Third problem: Continue With
Let’s modify slightly the code for using ContinueWith. When the “in continue with ” will be displayed ?
Console.WriteLine("start"); var t10Ex = test(delaySeconds: 10, throwEx: new ArgumentException("problem with argument")); var t20NotEx = test(delaySeconds: 20, throwEx: null); var t10ContinueWith = t10Ex.ContinueWith(async (previousTask) => { await Task.Delay(25 * 1000); Console.WriteLine("in continue with " + previousTask.IsCompletedSuccessfully); }).Unwrap(); try { await Task.WhenAll(t10Ex, t20NotEx ); } catch (Exception ex) { Console.WriteLine("err " + ex.GetType().Name); } finally { Console.WriteLine("in finally"); } Console.WriteLine("waiting in main"); await Task.Delay(100 * 1000); Console.WriteLine("finish");
Answer: : AFTER displaying “waiting in main” . Basically, you do not wait for ContinueWith, you wait for the first task in the ContinueWith construct ( t10Ex in our case)
And a question for you : Why do we need Unwrap ? ( Hint: try the code without and see the exception!)