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!)