c#:链式异步方法

c#: Chain asynchronous methods

我发现一段代码展示了如何链接异步方法。这是代码:

    public static class ExtensionMethod
    {
        public static async Task<TResult> MapAsync<TSource, TResult>(
            this Task<TSource> @this,
            Func<TSource, Task<TResult>> fn)
        {
            return await fn(await @this);
        }
    }

    public partial class Program
    {
        public async static Task<int> FunctionA
            (int a) => await Task.FromResult(a * 1);

        public async static Task<int> FunctionB(
            int b) => await Task.FromResult(b * 2);

        public async static Task<int> FunctionC(
            int c) => await Task.FromResult(c * 3);

        public async static void AsyncChain()
        {
            int i = await FunctionC(10)
                .MapAsync(FunctionB)
                .MapAsync(FunctionA);

            Console.WriteLine("The result = {0}", i);
        }
    }

但是我不明白为什么在扩展方法MapAsync里面我们有await fn(await @this)

有人能给我解释一下吗?

这是因为为了获得上一次调用的值(在本例中是存储在任务 @this 中的值),必须等待它。因为 await 现在正在该方法中使用并且必须标记为 async,所以您现在不能再简单地 return 来自 fn 的结果,因为它是一个任务。 (我相信你知道,用非常简单的术语来说,将方法标记为异步意味着方法签名有点忽略 Task 并且只想要一个泛型类型的实例作为 return 或者什么都没有,如果它没有使用 Task 的通用版本。)

为了回应您关于链接同步和异步方法的评论,这种使用 Task 的方法仍然适用于同步方法,您只需假装它的异步通过包装任务的结果(已标记为已完成)。像这样:

public async static Task<int> AsyncFunction(int x) 
    => await SomeAsyncMethodThatReturnsTaskOfInt();

public static Task<int> SyncFunction(int x) 
    => Task.FromResult(SomeSyncMethodThatReturnsInt());

public async static void AsyncChain()
{
    int i = await AsyncFunction(10)
        .MapAsync(SyncFunction);

    Console.WriteLine("The result = {0}", i);
}

可以从 FunctionA、FunctionB 和 FunctionC 定义中删除所有 async/awaits,因为它们可以 return 任务。

Stephen Cleary 在 Eliding await 上发表了一篇很好的文章,更好地解释了当该方法唯一要做的事情是 returning [= 时,何时应该和不应该使用 await 15=].

说了这么多,Gusman 的评论是完全正确的,对于一个相当简单的 ContinueWith