Using the async functionality available in .Net 4.5+, is there a way to initialize multiple local variables concurrently, without having to do it in two steps? is there another way to delay blocking the parent until an awaited variable is attempted to be dereferenced?
Example: I have a method in which I am given three IDs which are used to fetch objects from three separate services. Each service will take a non-trivial amount of time to return and I would like to minimize the clock time needed. There is no interdependency on the objects creation.
What I can do:
string MyFunc(long userId, long moduleId, long targetId) {
var userTask = _userRepo.Get(userId);
var moduleTask = _moduleRepo.Get(moduleId);
var targetTask = _targetRepo.Get(targetId);
var user = await userTask;
var module = await moduleTask;
var action = module.GetActionFor(user);
var target = await targetTask;
action.ApplyTo(target);
return string.Format("{0} begins {1} at {2}",
user.Name,
action.Description,
target.Location);
}
What can be done to remove the intermediary Tasks task variables?
I am looking for something more concise. I do not need the Tasks aside from the initial assignment and the results are used multiple times in the remainder of the operation.
Doing this results in essentially running the code synchronously. If each Get statement takes 1 second to return, the block takes 3 seconds to complete:
var user = await _userRepo.Get(userId);
var module = await _moduleRepo.Get(moduleId);
var target = await _targetRepo.Get(targetId);
Doing the following results in the code becoming hard to read, especially when the objects need to be used multiple times:
var user = _userRepo.Get(userId);
var module = _moduleRepo.Get(moduleId);
var target = _targetRepo.Get(targetId);
var action = (await module).GetActionFor(await user);
action.ApplyTo(await target);
var formattedString = string.Format("{0} begins {1} at {2}",
(await user).Name,
action.Description,
(await target).Location);
I don't believe there is a good way to get exactly what you want (at least not without some serious compile-time meta-programming).
The closest I could figure out is:
User user = null;
Module module = null;
Target target = null;
await RunAll(
async () => user = await _userRepo.Get(userId),
async () => module = await _moduleRepo.Get(moduleId),
async () => target = await _targetRepo.Get(targetId));
var action = module.GetActionFor(user);
action.ApplyTo(target);
var formattedString = string.Format("{0} begins {1} at {2}",
user.Name,
action.Description,
target.Location);
Where RunAll() is defined like this:
static Task RunAll(params Func<Task>[] funcs)
{
return Task.WhenAll(funcs.Select(f => f()));
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With