I'm still learning async/await
concepts so please bear with me. Suppose there is this legacy code that defines a contract for getting data from a data source (local database in the real case):
public interface IRepository<T> {
IList<T> GetAll();
}
In new code I have the following interface:
public interface IMyObjectRepository {
Task<IEnumerable<MyObject>> GetAllAsync();
}
The MyObjectRepository
class depends on IRepository<T>
like this:
public class MyObjectRepository : IMyObjectRepository
{
private readonly IRepository<Some.Other.Namespace.MyObject> repo_;
private readonly IDataMapper<Some.Other.Namespace.MyObject, MyObject> mapper_;
public BannerRepository(IRepository<Some.Other.Namespace.MyObject> repo, IDataMapper<Some.Other.Namespace.MyObject, MyObject> mapper)
{
repo_ = repo;
mapper_ = mapper;
}
}
How do I implement the IMyObjectRepository.GetAllAsync()
method in such a way that it makes sense in the context of asynchronous programming? Getting data from some local data source is an I/O bound operation, so the way I did it is:
public async Task<IEnumerable<MyObject>> GetAllAsync()
{
var tcs = new TaskCompletionSource<IEnumerable<MyObject>>();
try
{
GetAll(objects =>
{
var result = new List<MyObject>();
foreach (var o in objects)
{
result.Add(mapper_.Map(o));
}
tcs.SetResult(result);
});
}
catch (Exception e)
{
tcs.SetException(e);
}
return await tcs.Task;
}
private void GetAll(Action<IEnumerable<Some.Other.Namespace.MyObject>> handle)
{
IEnumerable<Some.Other.Namespace.MyObject> objects = repo_.GetAll<Some.Other.Namespace.MyObject>();
if (objects is null)
{
objects = Enumerable.Empty<Some.Other.Namespace.MyObject>();
}
handle(objects);
}
Does this make any sense? I did not want to use Task.Run()
because, the way I understand it, that wastes a thread for nothing in the case of an I/O bound operation which makes sense.