What is the correct way to use async/await in a recursive method?

.net, async-await, asynchronous, c#, recursion

Solution

While I have to say upfront that the intention of the method is not entirely clear to me, reimplementing it with a simple loop is quite trivial:

public async Task<string> ProcessStream(string streamPosition)
{
    while (true)
    {
        var stream = GetStream(streamPosition);

        if (stream.Items.Count == 0)
            return stream.NextPosition;

        foreach (var item in stream.Items)
        {
            await ProcessItem(item); //ProcessItem() is now an async method
        }

        streamPosition = stream.NextPosition;
    }
}

Recursion is not stack-friendly and if you have the option of using a loop, it's something definitely worth looking into in simple synchronous scenarios (where poorly controlled recursion eventually leads to `StackOverflowException`s), as well as asynchronous scenarios, where, I'll be honest, I don't even know what would happen if you push things too far (my VS Test Explorer crashes whenever I try to reproduce known stack overflow scenarios with `async` methods).

Answers such as Recursion and the await / async Keywords suggest that `StackOverflowException` is less of a problem with `async` due to the way the `async/await` state machine works, but this is not something I have explored much as I tend to avoid recursion whenever possible.

Problem

What is the correct way to use async/await in a recursive method? Here is my method: ``` public string ProcessStream(string streamPosition) { var stream = GetStream(streamPosition); if (stream.Items.count == 0) return stream.NextPosition; foreach(var item in stream.Items) { ProcessItem(item); } return ProcessStream(stream.NextPosition) } ``` And here is the method with async/await: ``` public async Task<string> ProcessStream(stringstreamPosition) { var stream = GetStream(streamPosition); if (stream.Items.count == 0) return stream.NextPosition; foreach(var item in stream.Items) { await ProcessItem(item); //ProcessItem() is now an async method } return await ProcessStream(stream.NextPosition); } ```

Original source

Related problems