使用LINQ创建可以接受的任务

时间:2017-07-12 19:05:55

标签: c# linq asynchronous async-await

我想创建一个等待任务的集合,以便我可以一起启动它们,并在完成时异步处理每个任务的结果。

我有这段代码和编译错误:

> cannot assign void to an implicitly-typed variable

如果我理解的话,Select返回的任务没有返回类型,即使传递的委托返回ColetaIsisViewModel,我想:

public MainViewModel()
{
    Task.Run(LoadItems);
}

async Task LoadItems()
{
    IEnumerable<Task> tasks = Directory.GetDirectories(somePath)
                            .Select(dir => new Task(() =>
                                new ItemViewModel(new ItemSerializer().Deserialize(dir))));

    foreach (var task in tasks)
    {
        var result = await task;  // <-- here I get the compilation error
        DoSomething(result);
    }
}

2 个答案:

答案 0 :(得分:9)

您不应该使用Task构造函数。

由于您正在调用同步代码(Deserialize),因此可以使用Task.Run

async Task LoadItems()
{
  var tasks = Directory.GetDirectories(somePath)
      .Select(dir => Task.Run(() =>
           new ItemViewModel(new ItemSerializer().Deserialize(dir))));

  foreach (var task in tasks)
  {
    var result = await task;
    DoSomething(result);
  }
}

或者,您可以使用Parallel或Parallel LINQ:

void LoadItems()
{
  var vms = Directory.GetDirectories(somePath)
      .AsParallel().Select(dir =>
           new ItemViewModel(new ItemSerializer().Deserialize(dir)))
      .ToList();

  foreach (var vm in vms)
  {
    DoSomething(vm);
  }
}

或者,如果您使Deserialize成为真正的async方法,那么您可以将其全部异步化:

async Task LoadItems()
{
  var tasks = Directory.GetDirectories(somePath)
      .Select(async dir => 
           new ItemViewModel(await new ItemSerializer().DeserializeAsync(dir))));

  foreach (var task in tasks)
  {
    var result = await task;
    DoSomething(result);
  }
}

另外,我建议你不要在构造函数中使用fire-and-forget。 There are better patterns for asynchronous constructors

答案 1 :(得分:2)

我知道这个问题已经得到解答,但你也可以这样做:

 var serializer = new ItemSerializer();
 var directories = Directory.GetDirectories(somePath);
 foreach (string directory in directories)
 {
      await Task.Run(() => serializer.Deserialize(directory))
      .ContinueWith(priorTask => DoSomething(priorTask.Result));                
 }

注意我拉出了序列化器实例化(假设没有副作用)。