初始化局部变量async

时间:2015-08-31 16:54:37

标签: c# async-await

使用.Net 4.5+中提供的异步功能,是否可以同时初始化多个局部变量,而无需分两步执行?是否有另一种方法可以延迟阻止父级直到一个等待变量被试图解除引用?

示例:我有一个方法,其中给了三个ID,用于从三个单独的服务中获取对象。每项服务都需要非常重要的时间才能返回,我希望尽量缩短所需的时钟时间。对象创建没有相互依赖性。

我能做什么:

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);
}

如何删除中间 Tasks 任务变量?

澄清:

我正在寻找更简洁的东西。除了初始赋值之外,我不需要任务,并且在操作的其余部分中多次使用结果。

这样做可以实现同步运行代码。如果每个Get语句需要1秒钟才能返回,则该块需要3秒才能完成:

var user = await _userRepo.Get(userId);
var module = await _moduleRepo.Get(moduleId);
var target = await _targetRepo.Get(targetId);

执行以下操作会导致代码难以阅读,尤其是在需要多次使用对象时:

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);

2 个答案:

答案 0 :(得分:1)

我不相信有一个很好的方法来获得你想要的东西(至少没有一些严肃的编译时元编程)。

我能想到的最接近的是:

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);

RunAll()的定义如下:

static Task RunAll(params Func<Task>[] funcs)
{
    return Task.WhenAll(funcs.Select(f => f()));
}

答案 1 :(得分:0)

如果每个Task实例具有相同的泛型类型参数(例如,Task<object>),那么您可以在一行中完成所有操作:

object[] results = await Task.WhenAll<object>(_userRepo.Get(userId), 
                                              _moduleRepo.Get(moduleId), 
                                              _targetRepo.Get(targetId));

return string.Format("{0} begins {1} at {2}",
                     ((User)results [0]).Name,
                     ((Module)results [1]).Description,
                     ((Target)results [2]).Location);

根据MSDN - Task.WhenAll

  

创建将在所有提供的任务完成后完成的任务