C# 异步初始化局部变量

C# 异步初始化局部变量,c#,async-await,C#,Async Await,使用.Net 4.5+中提供的异步功能,有没有一种方法可以同时初始化多个局部变量,而不必分两步执行?是否有其他方法延迟阻止父级直到尝试取消引用等待的变量 示例:我有一个方法,其中给了我三个ID,用于从三个独立的服务获取对象。每项服务都会花费大量的时间返回,我希望尽量减少所需的时钟时间。对象的创建没有相互依赖关系 我能做的是: string MyFunc(long userId, long moduleId, long targetId) { var userTask = _userRep

使用.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);
}
如何删除中间任务任务变量

澄清: 我在找更简洁的东西。除了初始分配,我不需要这些任务,并且在操作的剩余部分中会多次使用结果

这样做的结果是基本上同步运行代码。如果每个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);

如果每个
任务
实例具有相同的泛型类型参数(例如,
任务
),则可以在一行中完成所有操作:

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);
object[]results=wait Task.WhenAll(_userRepo.Get(userId),
_moduleRepo.Get(moduleId),
_targetRepo.Get(targetId));
返回string.Format(“{0}从{1}开始于{2}”,
((用户)结果[0])。名称,
((模块)结果[1])。说明,
((目标)结果[2])。位置);
根据:

创建一个任务,该任务将在所有提供的任务完成后完成


我不相信有一个好的方法可以得到你想要的(至少没有一些严肃的编译时元编程)

我能找到的最接近的答案是:

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()));
}
static Task RunAll(params Func[]funcs)
{
返回Task.WhenAll(funcs.Select(f=>f());
}

um,No:
无法将类型“void”隐式转换为“object[]”
@psaxton请参见编辑。尝试调用
Task.whalll(…)
。请注意,所有输入任务都必须返回一个
任务
'a'以进行工作,但将repos更改为返回
对象
似乎不是正确的方法。编写包装器方法来强制转换结果不会更好。您到底想实现什么?除了使用
Task.whalll
并发查询数据库之外,我看不出有什么问题。代码中没有任何中间任务<代码>等待不创建中间任务,它等待现有任务完成。也许真正的问题是“我如何等待多个任务完成?”@PanagiotisKanavos我想中间任务指的是中间变量。我知道使用
Task.whalll
等待多个任务,所以问题不是等待多个任务完成。我要寻找的是类似于埃菲尔铁塔中的SCOOP的东西——当变量第一次被解引用时自动等待
Task.Result
。令人遗憾的是,第二个代码块将在下一个语句之前产生并阻塞,而不是等待等待的变量被解引用以产生。这是用于日志记录的吗?(它看起来有点像一行日志/跟踪/调试代码)。。。如果是这样的话,我可以建议,与其从任务返回行并处理潜在的继续问题,等等,为什么不通过某种事件中介逻辑将字符串作为消息接收呢?例如,
EventAggregator
可以很好地满足这一需求。异步代码可以在最后一行中发布事件和负载字符串,而不是返回字符串。在事件处理程序中,您可以集中精力处理异步传入的数据。@code4life上面的代码仅用于示例。我可以看到它看起来像日志代码。如果更具体一些会有所帮助,那么实际的代码库就是聚合微服务操作/响应和数据库获取/更新。即使对于CodeReview帖子,尝试发布一个工作示例也会持续很长时间。