2

I have a simple set of code where I'm trying to implement an interface with an async method on it. The implementations thus far have all been things that utilize the async part of it and end up awaiting things. However, this new implementation of the interface is a simple synchronous operation-- no need for any awaiting.

When I implement it, first of all feels weird. Second, Visual Studio affirms my uncomfort with a warning telling me that the method is going to run synchronously-- which is what I'd expect, but the warning tells me it smells bad to VS, too. Is there a better pattern I should be following?

public interface IActivity
{
    async Task<bool> DoStuff();
}

//...

List<IActivity> activities = new List<IActivity>(){
   new SynchronousActivityA(),
   new SynchronousActivityB(),
   new AsynchronousActivityC()
};

foreach (var activity in activities){
    bool stuff = await activity.DoStuff();
    //do things with stuff.
}

I could just make my DoStuff() implementation do something like this:

await Task.Run(() => DoStuffSynchronously());

This would make my warning go away and feel a little more "right", but I'm not sure what benefit this would have over just writing the DoStuff() implementation to be as though it was a synchronous signature.

7
  • 2
    Don't include async in the interface definition; only where you need to use the await keyword, which is the implementation of the interface. Commented Jun 21, 2019 at 21:10
  • Remove the async keyword from the interface, that should be left up to the implementation. Commented Jun 21, 2019 at 21:10
  • Why are your synchronous operations implementing an asynchronous interface? Either have a synchronous interface for them to implement, since that's the behavior that they have, or provide an asynchronous implementation, because that's the contract they're agreeing to meet by implementing the interface. Anyone using this interface is going to expect any implementation to be asynchronous, because that's what it claims. You're breaking their code by not meeting that expectation. Commented Jun 21, 2019 at 21:12
  • 4
    Error CS1994 The 'async' modifier can only be used in methods that have a body. Commented Jun 21, 2019 at 21:20
  • async Task<bool> DoStuff(); on the interface doesn't even compile. It fails on a CS0106 error; The modifier 'async' is not valid for this item. Commented Jun 21, 2019 at 21:22

1 Answer 1

10

interface with an async method

Technically, "a method that returns Task<T>". async and await are implementation details.

A method returning an awaitable is a method that may be asynchronous. Synchronously returning a completed task is perfectly acceptable.

One way to do this is using Task.FromResult, but you would also want to be sure to capture exceptions and return them on the task as well:

try { return Task.FromResult(DoStuffSynchronously()); }
catch (Exception ex) { return Task.FromException<bool>(ex); }

This is a bit wordy. It does essentially the same thing as async without await, but you'd need to #pragma away the warning message, which is also awkward. If you do this often, you may want to define a utility method for it, something like TaskHelper.ExecuteAsTask in my AsyncEx library.

You should not use Task.Run just to "make code asynchronous". Task.Run uses a thread pool thread, which is not necessary in this case.

Sign up to request clarification or add additional context in comments.

2 Comments

"A method returning an awaitable is a method that may be asynchronous. Synchronously returning a completed task is perfectly acceptable". Very interesting! Is there a source of material on this? I have not found a good source yet in terms of design. Let's say designing an interface for file storage and one implementation is local file based and another HTTP, one can be synchronous, the other asynchronous, but would require two interfaces and more difficult code. It violates the "make synchronous library" methods because you might have to use it in a sync codebase. Seems like a complex topic?
@DavidAnderson: source of material - I'm not aware of anything official; just my blog. If you know one of your implementations is synchronous, then I'd recommend calling this out in the documentation but keeping the interface asynchronous. Note that this is a rare scenario.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.