“await”运算符只能用于异步lambda表达式

15

我正在尝试将文件列表复制到一个目录中。 我正在使用async / await。 但是我一直收到这个编译错误:

'await'操作符只能在异步lambda表达式中使用。请考虑使用'async'修饰符标记此lambda表达式。

这是我的代码:

async Task<int> CopyFilesToFolder(List<string> fileList, 
            IProgress<int> progress, CancellationToken ct)
{
    int totalCount = fileList.Count;
    int processCount = await Task.Run<int>(() =>
    {
        int tempCount = 0;
        foreach (var file in fileList)
        {
            string outputFile = Path.Combine(outputPath, file);

            await CopyFileAsync(file, outputFile); //<-- ERROR: Compilation Error 

            ct.ThrowIfCancellationRequested();
            tempCount++;
            if (progress != null)
            {
                progress.Report((tempCount * 100 / totalCount)));
            }

        }

        return tempCount;
    });
    return processCount;
}


private async Task CopyFileAsync(string sourcePath, string destinationPath)
{
    using (Stream source = File.Open(sourcePath, FileMode.Open))
    {
        using (Stream destination = File.Create(destinationPath))
        {
            await source.CopyToAsync(destination);
        }
    }

}

请问有人能指出我错过了什么吗?


1
你没有在lambda表达式中标记async关键字吗?基本上,如果你将lambda表达式提取到Task.Run内部,它将不是一个async方法,因此你无法等待结果。 - Daniel Kelley
await Task.Run<int>(() => ... -- lambda表达式不是async - Jon
1
这段代码应该不使用Lambda或Task.Run,因为它只有IO限制。请查看http://pastebin.com/p83gkkTk获取示例解决方案(我会将其作为答案发布,但已关闭)。 - Tim S.
@TimS,谢谢你,是的,我同意。 - abhilash
1个回答

34
int processCount = await Task.Run<int>(() =>

应该是这样的

int processCount = await Task.Run<int>(async () =>

记住,lambda 只是定义 方法 的简写。因此,您的外部方法是 async,但在这种情况下,您尝试在 lambda 中使用 await(lambda 是与您的外部方法不同的不同 方法)。因此,您的 lambda 也必须标记为 async


1
await Task.Run<int>(async () => 这段代码看起来有些多余,有更好的写法吗? - Tim S.
1
@TimS.:不是的;每个部分都很重要,具有不同的含义。async () => 使lambda变成异步的,Task.Run在线程池线程上运行该lambda,而await表示调用方法正在(异步地)等待该lambda完成。 - Stephen Cleary
2
抱歉,我的表述不够清晰:Task.Run 似乎通常用于卸载本来会是同步的、CPU 密集型工作。但这里似乎没有任何重要的 CPU 工作,只有 IO 密集型工作。因此,是否有可能并且更好地以一种不使用 Task.Run,而只是等待异步方法的方式编写它呢? - Tim S.
2
啊,我明白了。是的,在I/O工作中使用Task.Run是多余的,而且在这里似乎确实如此。 - Stephen Cleary
1
这正是我所需要的,谢谢! Assert.ThrowsAsync<InvalidOperationException>(async () => await this.eligibilityService.GetEligibility(eligibilityCriteriaModel)).Result; - Todd Vance
1
@ToddVance:我建议使用await代替Result - Stephen Cleary

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接