Skip to main content

This recipe will describe how to translate event-based asynchronous operations to tasks. In this recipe, you will find a solid pattern that is suitable for every event-based asynchronous API in the .NET Framework class library.

using System;
using System.ComponentModel;
using System.Threading;
using System.Threading.Tasks;

//
// Translate Event-Based Asynchronous Operations to Tasks
//
// This recipe will describe how to translate event-based asynchronous
// operations to tasks. In this recipe, you will find a solid pattern that is
// suitable for every event-based asynchronous API in the .NET Framework class
// library.
//
// How it works...
//
// This is a very simple and elegant example of converting EAP patterns to
// tasks. The key point is to use the TaskCompletionSource<T> type, where T is
// an asynchronous operation result type.
//
// It is also important to not forget to wrap the tcs.SetResult method call into
// the try - catch block to guarantee that the error information is always set
// to the task completion source object. It is also possible to use the
// TrySetResult method instead of SetResult to make sure that the result has
// been set successfully.
//

namespace Chapter4.Recipe5
{
    class Program
    {
        static void Main(string[] args)
        {
            var tcs = new TaskCompletionSource<int>();

            var worker = new BackgroundWorker();
            worker.DoWork += (sender, eventArgs) =>
            {
                eventArgs.Result = TaskMethod("Background worker", 5);
            };

            worker.RunWorkerCompleted += (sender, eventArgs) =>
            {
                if (eventArgs.Error != null)
                {
                    tcs.SetException(eventArgs.Error);
                }
                else if (eventArgs.Cancelled)
                {
                    tcs.SetCanceled();
                }
                else
                {
                    tcs.SetResult((int)eventArgs.Result);
                }
            };

            worker.RunWorkerAsync();

            int result = tcs.Task.Result;

            Console.WriteLine("Result is: {0}", result);
        }

        static int TaskMethod(string name, int seconds)
        {
            Console.WriteLine(
            	"Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
            	name,
            	Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);

            Thread.Sleep(TimeSpan.FromSeconds(seconds));

            return 42 * seconds;
        }
    }
}