What to do when interface implementation does not provide async

Viewed 1594

Let's say I have an interface:

interface ILoader()
{
    Task<Data> LoadAsync(int id);
}

I have two implementations of this interface:

class NiceDataBase : ILoader 
{
    public async Task<Data> LoadAsync(int id)
    {
        //this database has async way of fetching the data
        return await NiceDataBaseDriver.LoadDataAsync(id);
    }
}

class NotNiceDataBase : ILoader 
{
    public async Task<Data> LoadAsync(int id)
    {
        //this database's driver does not have aysnc methods, because it's old or done poorly.
        return await Task.Run(() => NotNiceDataBaseDriver.LoadData(id));
    }
}

The NotNiceDataBase doesn't provide real async way to load the data, that's why I actually run it on a new thread, which, as I understand, is not really async, because real async does not use a new thread. Is my implementation of NotNiceDataBase a good one then? It kind of cheats the user to think that he is running a real async operation.

What is the optimal way to deal with such situation? I think that the client of NotNiceDataBase should be completely aware what he is doing, otherwise he can't control performance of hiw application well.

My interface could have additional Load method. But in such case, what's the real benefit here? Still LoadAsync of NotNiceDataBase would need to have some implementation. Throwing NotImplementedException is never a good solution I think.

2 Answers

As you know async is an implementation detail and you can not define async on interfaces. So all you have to do is

public class NotNiceDataBase : ILoader
{
    public Task<Data> LoadAsync(int id)
    {
        //this database's driver does not have aysnc methods, because it's old or done poorly.    
        var result = NotNiceDataBaseDriver.LoadData(id);
        return Task.FromResult(result);
     }
}

Simply run the method synchronously and return a completed task e.g.

class NotNiceDataBase : ILoader 
{
    public Task<Data> LoadAsync(int id)
    {
        var data = NotNiceDataBaseDriver.LoadData(id);
        return Task.From(data);
    }
}

You say

I think that the client of NotNiceDataBase should be completely aware what he is doing, otherwise he can't control performance of hi(s) application well.

I disagree, if performance is an issue and if they've identified that it's the call to NotNiceDataBase then they can do something about it.

elaboration

Time worrying about how the client is using the interface is almost certainly1 time wasted, and isn't even "premature optimization" but is existential angst over someone else's unknown optimization needs.

1Unless you are your own client, then it's still probably time wasted.

Related