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

hel*_*ker 1 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

Ste*_*ary 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);
  }
}
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用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);
  }
}
Run Code Online (Sandbox Code Playgroud)

或者,如果你创建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);
  }
}
Run Code Online (Sandbox Code Playgroud)

另外,我建议你不要在构造函数中使用fire-and-forget.异步构造函数有更好的模式.