how to do it better replace continueWith to async/await in C#

621 Views Asked by At

I have C# code:

public class SimpleClass{

    public Task<TestClass> WaitForUserInput(IResource resource, CancellationToken token)
    {
        var button = resource.GetResource();

        var taskCompletionSource = new TaskCompletionSource<UserActionResult>();
        IDisposable cancellationTokenReg = token.Register(
                                      () => taskCompletionSource.SetResult(new TestClass()));

        var taskDisposeTokenUnreg = taskCompletionSource.Task.ContinueWith(
            task =>
                {
                    cancellationTokenReg.Dispose();
                     return task.Result;
                 });

        button.TouchEvent += Subscribe;
        button.Disabled = true;

        return taskDisposeTokenUnreg;
    }
}       

I need replace continueWith to await. And I try in this example:

public class SimpleClass{

    public async Task<TestClass> WaitForUserInput(IResource resource, CancellationToken token)
    {
        var button = resource.GetResource();

        var taskCompletionSource = new TaskCompletionSource<UserActionResult>();
        IDisposable cancellationTokenReg = token.Register(
                                      () => taskCompletionSource.SetResult(new TestClass()));

        var taskDisposeTokenUnreg = await taskCompletionSource.Task
        cancellationTokenReg.Dispose();
        return taskDisposeTokenUnreg.Result;

        button.TouchEvent += Subscribe;
        button.Disabled = true;

        return taskDisposeTokenUnreg;
    }
}     

But taskDisposeTokenUnreg has no field Result and and you can’t write like that await taskCompletionSource.Task.Result. How best to replace this code?

2

There are 2 best solutions below

0
On

When you use the await operator on a Task, the value you get is the result of the Task.

So in your case, taskDisposeTokenUnreg will already be the UserActionResult value you are looking for. You can just return taskDisposeTokenUnreg.

0
On

Your original method has a synchronous signature; all the code in that method (except the delegates) is executed immediately. The ContinueWith delegate is the only code that executes later, after the taskCompletionSource.Task completes. So, to duplicate this behavior, you need to move the ContinueWith delegate to the end of the method, so all the synchronous code executes first just like it did before:

public async Task<TestClass> WaitForUserInput(IResource resource, CancellationToken token)
{
  var button = resource.GetResource();

  var taskCompletionSource = new TaskCompletionSource<UserActionResult>();
  IDisposable cancellationTokenReg = token.Register(
                                      () => taskCompletionSource.SetResult(new TestClass()));

  button.TouchEvent += Subscribe;
  button.Disabled = true;

  var result = await taskCompletionSource.Task;
  cancellationTokenReg.Dispose();
  return result;
}

Once you're using async/await, then you can simplify further by using a using declaration:

public async Task<TestClass> WaitForUserInput(IResource resource, CancellationToken token)
{
  var button = resource.GetResource();

  var taskCompletionSource = new TaskCompletionSource<UserActionResult>();
  using var cancellationTokenReg = token.Register(
                                      () => taskCompletionSource.SetResult(new TestClass()));

  button.TouchEvent += Subscribe;
  button.Disabled = true;

  return await taskCompletionSource.Task;
}