56

I have an application. This application uses an interface to access the database. This interface can be implemented by many classes. For example, one uses EF 4.4, but other classes can use EF5 that is more efficient. In the future perhaps I will use EF6 because it uses async methods. In this example all the methods use EF, but perhaps other options can be use other ways.

The application is coded once, using the interface, and according to the config file, use one implementation or the other, so I only need to modify the code in one place, the constructor, to add the new option in the instantiation of the class that is assigned to the interface.

At the moment all the methods of the classes are not async, but in the future if I use EF6 I would like to use the async methods, so I don't know if it is possible that the class that use EF6 and implements the interface can use the async methods.

For the async methods of EF6, I would use the async/awiat pattern, so in the method of my class I need to use the async attribute. This lets me use the await keyword when I call to the async method of EF6.

But this class can implement the interface that in a first time is for synchronous methods?

Is there some way that in the main application I can use many implementations without the need to modify the code? Some implementations will use async methods while others will be synchronous.

3
  • 3
    Keep in mind that async isn't a part of the signature; an async and a non-async method can both implement the same interface method.
    – Servy
    Commented Nov 26, 2012 at 21:39
  • 1
    It's not the method that's awaitable, it's the (return) type.
    – rism
    Commented Oct 10, 2015 at 2:33
  • 2
    Too much explanation for a simple question. IMHO. Commented Jan 5, 2016 at 10:18

1 Answer 1

68

async isn't a part of the signature, so you don't actually need to be concerned with whether the method implementing the interface is async or not, you only need to be concerned with the types of the properties, the return type, the name of the method, and the accessibility.

The real difference is that your async methods will need to return a Task or a Task<T>, whereas the non-async methods are most likely currently returning void or some type, T directly.

If you want to "future proof" your application one option is to ensure that all of your interfaces return Task or Task<T> and that for your EF4/EF5 implementations you wrap your results in a completed task even though they're executed synchronously.

Task.FromResult was added in .NET 4.5, but if you don't have it you can write your own easily enough:

public static Task<T> FromResult<T>(T result)
{
    var tcs = new TaskCompletionSource<T>();
    tcs.SetResult(result);
    return tcs.Task;
}

You can also write a CompletedTask method that simply returns a task that has already completed: (It caches a single task for efficiency reasons.)

private static Task _completedTask;
public static Task CompletedTask()
{
    return _completedTask ?? initCompletedTask();
}

private static Task initCompletedTask()
{
    var tcs = new TaskCompletionSource<object>();
    tcs.SetResult(null);
    _completedTask = tcs.Task;
    return _completedTask;
}

Those two methods will simplify the process of having all of your methods returning some type of Task, although doing this will make your code a bit messier until you're able to use C# 5.0 to be able to await the result.

4
  • so the only solution is force to all the classes to return a task? Commented Nov 26, 2012 at 22:01
  • 1
    Well, it's not the only solution. It's the best one that I could come up with. If you have C# 5.0 but just not EF 6.0 then you can still await the results of the method call (even if they're already completed) which would make it not too terrible.
    – Servy
    Commented Nov 26, 2012 at 22:02
  • 7
    In a situation like this (where your operations are naturally asynchronous), you can either make all the methods return Task or create both synchronous and asynchronous methods side-by-side. Commented Nov 26, 2012 at 22:15
  • The issue is that sync and async side by side is leaky abstraction. They both doing the same thing. And many times you have implementations where nothing async happens but it has to go down that road. And then it breaks tell don't ask principle. I should have to ask "are you sync or async buddy?" We should just be interested in the contract.. Do this .. thank you
    – Piotr Kula
    Commented Nov 17, 2022 at 21:44

Not the answer you're looking for? Browse other questions tagged or ask your own question.