Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implement async interface with synchronous code

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.

like image 633
scott degen Avatar asked Jun 08 '26 07:06

scott degen


1 Answers

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.

like image 88
Stephen Cleary Avatar answered Jun 10 '26 18:06

Stephen Cleary