Anders Gustafsson
Anders Gustafsson

Reputation: 15971

How to implement interface method that returns Task<T>?

I have an interface

interface IFoo
{
  Task<Bar> CreateBarAsync();
}

There are two methods to create Bar, one asynchronous and one synchronous. I want to provide an interface implementation for each of these two methods.

For the asynchronous method, the implementation could look like this:

class Foo1 : IFoo
{
  async Task<Bar> CreateBarAsync()
  {
    return await AsynchronousBarCreatorAsync();
  }
}

But HOW should I implement the class Foo2 that uses the synchronous method to create Bar?

I could implement the method to run synchronously:

  async Task<Bar> CreateBarAsync()
  {
    return SynchronousBarCreator();
  }

The compiler will then warn against using async in the method signature:

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Or, I could implement the method to explicitly return Task<Bar>. In my opinion the code will then look less readable:

  Task<Bar> CreateBarAsync()
  {
    return Task.Run(() => SynchronousBarCreator());
  }

From a performance point of view, I suppose both approaches have about the same overhead, or?

Which approach should I choose; implement the async method synchronously or explicitly wrap the synchronous method call in a Task?

EDIT

The project I am working on is really a .NET 4 project with async / await extensions from the Microsoft Async NuGet package. On .NET 4, Task.Run can then be replaced with TaskEx.Run. I consciously used the .NET 4.5 method in the example above in the hope of making the primary question more clear.

Upvotes: 43

Views: 20531

Answers (4)

Yuval Itzchakov
Yuval Itzchakov

Reputation: 149518

If you're using .NET 4.0, you can use TaskCompletionSource<T>:

Task<Bar> CreateBarAsync()
{
    var tcs = new TaskCompletionSource<Bar>();
    tcs.SetResult(SynchronousBarCreator());
    return tcs.Task
}

Ultimately, if theres nothing asynchronous about your method you should consider exposing a synchronous endpoint (CreateBar) which creates a new Bar. That way there's no surprises and no need to wrap with a redundant Task.

Upvotes: 8

noseratio
noseratio

Reputation: 61656

To complement others answers, there's one more option, which I believe works with .NET 4.0 too:

class Foo2 : IFoo
{
    public Task<Bar> CreateBarAsync()
    {
        var task = new Task<Bar>(() => SynchronousBarCreator());
        task.RunSynchronously();
        return task;
    }
}

Note task.RunSynchronously(). It might be the slowest option, compared to Task<>.FromResult and TaskCompletionSource<>.SetResult, but there's a subtle yet important difference: the error propagation behavior.

The above approach will mimic the behavior of the async method, where exception is never thrown on the same stack frame (unwinding it out), but rather is stored dormant inside the Task object. The caller actually has to observe it via await task or task.Result, at which point it will be re-thrown.

This is not the case with Task<>.FromResult and TaskCompletionSource<>.SetResult, where any exception thrown by SynchronousBarCreator will be propagated directly to the caller, unwinding the call stack.

I have a bit more detailed explanation of this here:

Any difference between "await Task.Run(); return;" and "return Task.Run()"?

On a side note, I suggest to add a provision for cancellation when designing interfaces (even if cancellation is not currently used/implemented):

interface IFoo
{
    Task<Bar> CreateBarAsync(CancellationToken token);
}

class Foo2 : IFoo
{
    public Task<Bar> CreateBarAsync(CancellationToken token)
    {
        var task = new Task<Bar>(() => SynchronousBarCreator(), token);
        task.RunSynchronously();
        return task;
    }
}

Upvotes: 6

Guillaume
Guillaume

Reputation: 13128

When you have to implement an async method from an interface and your implementation is synchronous, you can either use Ned's solution:

public Task<Bar> CreateBarAsync()
{
    return Task.FromResult<Bar>(SynchronousBarCreator());
}

With this solution, the method looks async but is synchronous.

Or the solution you proposed:

  Task<Bar> CreateBarAsync()
  {
    return Task.Run(() => SynchronousBarCreator());
  }

This way the method is truly async.

You don't have a generic solution that will match all cases of "How to implement interface method that returns Task". It depends on the context: is your implementation fast enough so invoking it on another thread is useless? How is this interface used a when is this method invoked (will it freeze the app)? Is it even possible to invoke your implementation in another thread?

Upvotes: 27

NeddySpaghetti
NeddySpaghetti

Reputation: 13495

Try this:

class Foo2 : IFoo
{
    public Task<Bar> CreateBarAsync()
    {
        return Task.FromResult<Bar>(SynchronousBarCreator());
    }
}

Task.FromResult creates an already completed task of the specified type using the supplied value.

Upvotes: 24

Related Questions