我想创建一个等待任务的集合,以便我可以一起启动它们,并在完成时异步处理每个任务的结果。
我有这段代码和编译错误:
> 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);
}
}
答案 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));
}
注意我拉出了序列化器实例化(假设没有副作用)。