在上一个任务完成后调用异步方法

Call async method after previous task completes

我最近了解到 Task.ContinueWith 并试图将其应用到我已有的一些现有代码中以获得更好的性能。我有这样的东西:

        public static async Task<TResult> DoWork<T, TResult>(T value)
        {
            var fooResult = await Foo(value);
            return await Bar<TResult>(fooResult);
        }

        private static Task<MyClass> Foo<T>(T value)
        {
            return GetMyClassFromValueAsync(value);
        }

        private static Task<TResult> Bar<TResult>(MyClass myClass)
        {
            return myClass.DoOperationAsync();
        }

我在想我可以通过做这样的事情来改进它:

        public static Task<TResult> DoWork<T, TResult>(T value)
        {
            return Foo(value).ContinueWith(fooResult => Bar<TResult>(fooResult.Result));
        }

我 运行 遇到的问题是 ContinueWith returns 在这种情况下是 Task<Task<TResult>> 的一种类型,因为它将我的异步调用包装在另一个任务中。我找到的唯一解决方案是做这样的事情:

        public static async Task<TResult> DoWork<T, TResult>(T value)
        {
            return await await Foo(value).ContinueWith(fooResult => Bar<TResult>(fooResult.Result));
        }

但这看起来不对,迫使我等待它。有没有更好的方法来处理这种情况?

这些调用在幕后也发生了很多事情,所以如果我采用了错误的方法或者我的直觉让我误入歧途而我应该坚持原来的方法,请告诉我原因,这样我才能学习和提高。谢谢!

你们很亲近。您缺少最后的 UnWrap 方法。

public static async Task<TResult> DoWork<T, TResult>(T value)
        {
            return await await Foo(value).ContinueWith(fooResult => Bar<TResult>(fooResult.Result)).UnWrap();
        }

但实际上,您使用 ContinueWith 所做的并不比您之前使用 await 的效率更高。我相信 await 只是 ContinueWith 的语法糖。我个人觉得 await 更容易阅读。

您希望将 promises 和 return 最终结果链接在一起,对此有一个扩展方法 Unwrap

示例:

class Program
{
    static void Main(string[] args)
    {

        var finalWork = Work().ContinueWith(work => MoreWork(work.Result)).Unwrap();
        finalWork.Wait();
        var finalWorkResult = finalWork.Result;
        Console.WriteLine(finalWorkResult);

    }

    private static Task<string> MoreWork(string s)
    {
        return Task.FromResult($"{s} done... now more work.");
    }

    private static Task<string> Work()
    {
        return Task.FromResult("Work work");
    }
}

Using ContinueWiht can be problematic 而且不必要地复杂。

拥抱一下async-await:

public static async Task<TResult> DoWork<T, TResult>(T value)
{
    return await Bar<TResult>(await Foo(value));
}