user7994414
user7994414

Reputation:

Call async method after previous task completes

I recently learned about Task.ContinueWith and am trying to apply it to some existing code I have for better performance. I have something like this:

        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();
        }

and was thinking I could improve it by doing something like this instead:

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

The problem that I'm running into is that ContinueWith returns a type of Task<Task<TResult>> in this case because it wraps my async call in another task. The only solution I've found is to do something like this:

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

but that just looks wrong and forces me to await it. Is there a better way to handle this situation?

There's also a lot happening behind the scenes with these calls, so if I'm taking the wrong approach or my intuition is leading me astray and I should stick with my original approach, please let me know why so I can learn and improve. Thanks!

Upvotes: 0

Views: 457

Answers (3)

Paulo Morgado
Paulo Morgado

Reputation: 14856

Using ContinueWiht can be problematic and it's unnecessarily complicated.

Just embrace async-await:

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

Upvotes: 1

arynaq
arynaq

Reputation: 6870

You are looking to chain together promises and return the final result, there is an extension method Unwrap for this.

Example:

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");
    }
}

Upvotes: 1

peinearydevelopment
peinearydevelopment

Reputation: 11474

You are very close. You are missing the UnWrap method at the end.

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

In reality though, what you are doing with ContinueWith is no more efficient than what you had before with the await. I believe the await is just syntactic sugar for ContinueWith. I personally find await much easier to read.

Upvotes: 1

Related Questions