28

I have an Interface I that is implemented in two places like:

interface I 
{ 
   Task DoSomething();
}

The interface has async Task DoSomething method API that is then implemented in class A like:

class A : I {....}

class B : I {....}

In class A, the implementation of DoSomething is like below and that is OK:

public async Task DoSomething()
{
    if (...)
    {
        await DoIt();
    }
}

However, in class B, the implementation of DoSomething() should not do anything. So, its implementation looks like this:

public async Task DoSomething()
{
    // nothing
}

This compiles but I am not sure how correct it is do do something like this beside the fact that the method is useless.

But being "useless" in this case is ok in this case since it is implemented just because it is required by class B implementing the interface I.

I wonder if this is a correct way to implement a method that returns async Task but has no await or return? I know that this method will simple do nothing and execute synchronously as there is no call to await.

UPDATE: Similar questions have been asked here on SO and I have checked all of them before asking this one. None is asking what I am asking though

pixel
  • 9,653
  • 16
  • 82
  • 149
  • 4
    You only mark a method as `async` if you're planning on using an `await` (directly) inside of it. The fact that it returns a `Task` is enough to satisfy the interface; `async/await` are irrespective of interfaces. – Kenneth K. Nov 08 '17 at 19:06

2 Answers2

64
public Task DoSomething()
{
    return Task.CompletedTask;
}

No need for the async.

If you're using an older version of .NET, use this:

public Task DoSomething()
{
    return Task.FromResult(0);
}

If you find you need to return a result but you still dont need to await anything, try;

public Task<Result> DoSomething()
{
    return Task.FromResult(new Result())
}

or, if you really want to use async (not recommended);

public async Task<Result> DoSomething()
{
    return new Result();
}
Roman Hwang
  • 405
  • 5
  • 10
sellotape
  • 8,034
  • 2
  • 26
  • 30
  • 4
    I get that the fourth option is not recommended but you don't give a reason why? – m3z Jul 09 '18 at 13:45
  • 2
    @m3z - the compiler will generate a warning along the lines of "the async method lacks await operators and will run synchronously". More importantly, though, the compiler will generate an entire `IAsyncStateMachine` for what is otherwise a very simple method. An intelligent compiler might optimise this away, but from a brief visit to https://sharplab.io/, it seems there's every chance it won't, and on NET47x it JITs to 259 bytes of x86 assembly for the async method vs 71 for the sync. – sellotape Jul 09 '18 at 15:51
  • Makes sense. Thanks – m3z Jul 10 '18 at 18:59
  • 1
    `No need for the async` - but does it harm? I kinda like to trade the `return Task.ComletedTask;` line for an `async` keyword if it doesn't harm in any way.. – Vegar Apr 09 '19 at 10:11
  • 1
    @vegar- As sellotape mentioned, async methods have an overhead associated with them and should only be used to implement something that is I/O intensive (like writing to a file, making an external Http call). For simple methods or the ones that are "Compute intensive" (like adding two numbers, calculating factorial of 10^10), async doesn't help and thus creating additional additional state overhead is unnecessary. – GiriB May 15 '19 at 09:17
  • for the #4, it is better to do `return await Task.FromResult(new Result());` – tom Feb 21 '20 at 01:02
11

I see that most people prefer to leave out the async and use Task.ComletedTask instead. But even if await is not used, there is still a big difference in exception handling

Consider the following example

static async Task Main(string[] args)
{

    Task task = test(); // Will throw exception here
    await task;

    Task taskAsync = testWithAsync();
    await taskAsync; // Will throw exception here
}

static Task test()
{
    throw new Exception();
    return Task.CompletedTask; //Unreachable, but left in for the example
}

static async Task testWithAsync()
{
    throw new Exception();
}

Using

test().ContinueWith(...); or Task.WhenAll(test())

may result in unexpected behaviour.

Therefore, I prefer async instead of Task.CompletedTask or Task.FromResult.

Pepernoot
  • 3,409
  • 3
  • 21
  • 46
  • 1
    "may result in unexpected behaviour" is a bit vague. Maybe you can explain why you think it could cause "unexpected behaviour". – Rev Sep 22 '22 at 11:43