logo

C# How to use asychronous tasks to return results

When the c# compiler encounters an await in an async method, it reformats it into a task.Run on the same thread as the async method. Now, there is a problem updating the User Interface because they share the same thread. Using the await on a code will create a continuation block for completion after the async code is done. You won't get a "marshalled from a different thread" error by using await with async or using continueWith and putting your UI update code in the continueWith code block.

ContinueWith

The ContinueWith is execute by the async thread doing work. The Task<TResult> is return by the async function. The value of the async method can by assessed by the Result variable.


 Task resultTask = Task.Run(async () => await unitOfWork.addressBookRepository.GetObjectAsync(addressId));

                Task continueTask = resultTask.ContinueWith(
               query =>
               {
                   formData.AddressId = query.Result.AddressId;
                   formData.Name = query.Result.Name;
                   ....
                   MessageBox.Show(formData.Name);
               });


                Task.WaitAll(resultTask);

Await

The await keyword in the async method specifics a point the c# compiler can split the code into a continuation on the thread doing the work.

 private void DoSomethingFnc1()
        {
            Console.WriteLine("Fnc1");
        }
        private void DoSomethingFnc2()
        {
            Console.WriteLine("Fnc2");
        }
        [TestMethod]
        public async Task TestAwaitAsync()
        {
            List listTask = new List();
            Task firstTask = Task.Run(() => { DoSomethingFnc1(); });
            Task secondTask = Task.Run(() => { DoSomethingFnc2(); });
            listTask.Add(firstTask);  // await firstTask;
            listTask.Add(secondTask); // await secondTask;
            Task.WaitAll(listTask.ToArray());
          
            Console.WriteLine("Done");
        }

How to get Results from a Task

The task returns a list of doubles for TResult. I can enumerate the Result because it is IList of doubles


      IList<double> DoCalculationFnc1()
        {
            IListt<double> list = new List<double>();
            for (int i = 0; i t< 100; i++)
            {
                list.Add(Math.Pow((double)i, 2.0));

            }
            return list;
        }
        [TestMethod]
        public async Task TestResultAsync()
        { 
            Task<IList<double>> pow2ResultTask = Task.Run(() => DoCalculationFnc1());
            await pow2ResultTask;
            int index = 0;
            foreach (var item in pow2ResultTask.Result)
            {
                Console.WriteLine($"pow {index}^2={ item}");
                index++;
            }

        }

ConfigureAwait

await function().ConfigureAwait(false) will run the method on a separate thread from the UI thread. The await call will instantaneous return control back to the UI thread. In the code example, the doLongRunningFnc1 processes a 100 numbers raise to the third power without blocking the UI thread.


        private async Task DoLongRunningFnc()
        {
            IList<double> list = new List<double>();
            Task longRunningTask = Task.Run(() =>
            {
                for (int i = 0; i < 60; i++)
                {
                    list.Add(Math.Pow((double)i, 3.0));
                    Task.Delay(1000);
                }
            });
            await longRunningTask;
            int index = 0;
            foreach (var item in list)
            {
                Console.WriteLine($"{index} pow 3 = {item}");
                index++;
            }
        }
        [TestMethod]
    public async Task TestConfigureAwaitAsync()
    {
        await DoLongRunningFnc().ConfigureAwait(false);
    }

PLinq

PLinq divides data insto partitions then uses tasks to query each partition looking for criteria matches. The results are combined into an enumerable set.

.AsParallel
s