private static Task <TResult> ExecuteAsync <TResult>(SpreadsheetsService service, object userData, IAggregateProgress progress, CancellationToken cancellationToken, Func <AsyncOperationCompletedEventArgs, TResult> getResult)
            where TResult : AtomBase
        {
            var taskSource = new TaskCompletionSource <TResult>();

            AsyncOperationProgressEventHandler progressHandler = null;

            if (progress != null)
            {
                progressHandler = (sender, eventArgs) =>
                {
                    if (eventArgs.UserState == userData)
                    {
                        progress.Report(eventArgs.ProgressPercentage);
                    }
                };

                service.AsyncOperationProgress += progressHandler;
            }

            AsyncOperationCompletedEventHandler evnetHandler = null;

            evnetHandler = (sender, eventArgs) =>
            {
                if (eventArgs.UserState == userData)
                {
                    service.AsyncOperationCompleted -= evnetHandler;
                    if (progress != null)
                    {
                        progress.Report(100);
                        service.AsyncOperationProgress -= progressHandler;
                    }

                    if (eventArgs.Error != null)
                    {
                        taskSource.TrySetException(eventArgs.Error);
                    }
                    else
                    {
                        taskSource.TrySetResult(getResult(eventArgs));
                    }
                }
            };

            service.AsyncOperationCompleted += evnetHandler;

            cancellationToken.Register(() =>
            {
                if (taskSource.TrySetCanceled())
                {
                    service.AsyncOperationCompleted -= evnetHandler;
                    if (progress != null)
                    {
                        service.AsyncOperationProgress -= progressHandler;
                    }

                    service.CancelAsync(userData);
                }
            });

            return(taskSource.Task);
        }