使用await的异步lambda表达式会返回Task吗?

22

我有以下代码:

            // Get all of the files from the local storage directory.
        var files = await folder.GetFilesAsync();

        // Map each file to a stream corresponding to that file.
        var streams = files.Select(async f => { return await f.OpenStreamForWriteAsync(); });

我本来期望streamsIEnumerable<Stream>类型,但事实上它的类型是IEnumberable<Task<Stream>>,如果我省略await关键字的话,那就是我所期望的。而OpenStreamForWriteAsync方法的返回类型是Task<Stream>,那么等待它的结果不应该是一个Stream吗?

所以,为什么这个await语句返回的是一个Task呢?

感谢您的帮助。


3
异步方法始终返回Task<T>Task。Select本身不关心返回类型,因此它会投影一个可枚举的Task,因为您的选择lambda是异步的。您可以遍历集合并等待Stream。 - vcsjones
好的,一个人可以编写一个“async void”方法,这就是我认为在这里发生的情况。我该如何修复它? - Matthew H
如果是void,则您将不知道异步任务何时完成,也无法获取任何结果(因为没有结果)。只有当它是事件处理程序时,您才真正希望拥有void异步方法,但这不是。 - Servy
如果我编写一个异步 void 方法,它不需要被等待,而异步 Task 方法则需要。那么它们如何等价呢? - Matthew H
2
@MatthewH vscjones可能的意思是,每当你有一个非async方法返回void并将其转换为async方法时,应该将其返回类型从void更改为Task,因为Task是调用者知道它何时完成的一种方式,但表示它没有结果。返回void只意味着调用者甚至无法知道何时完成。 - Servy
4
为什么使用 return await 语句会返回一个 Task 呢?简单来说,await 关键字将 Task<T> 解封成 T,而 async 关键字会将 T 封装回 Task<T>。我赞同 Servy 的回答。 - Stephen Cleary
2个回答

16

所有async方法返回的类型为voidTaskTask<TResult>。Lambda表达式只是一个匿名方法,因此仍然适用这个规则。它本质上与这个命名方法相同:

private static async Task<Stream> Foo(TypeGOesHere f )
{
    return await f.OpenStreamForWriteAsync(); 
}
为了使它返回一个Stream,它需要是一个阻塞方法,而不是异步方法:
private static Stream Foo(TypeGOesHere f )
{
    return f.OpenStreamForWriteAsync().Result; 
}

你可能不想要那个。

如果有帮助的话,你可以使用Task.WhenAll将你的IEnumerable<Task<Stream>>转换为Task<Stream[]>

Task<Stream[]> resultTask = Task.WhenAll(streams);

或者更好的方法是将封闭的方法设为异步,然后使用 var streams = files.Select(await f.OpenStreamForWriteAsync());。需要有 async 修饰符的不是 lambda 表达式。 - shipr

4
这难道不是最佳解决方案吗?
        // Get all of the files from the local storage directory.
    var files = await folder.GetFilesAsync();

    // Map each file to a stream corresponding to that file and await the Task that waits for all tasks to complete? maybe thats whats being implied above...
    var streams = await Task.WhenAll(files.Select(async f => { return await f.OpenStreamForWriteAsync(); }));

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