A more “batteries-included” implementation of this kind of thing, including language support, is now available as of C# 8.0.
Now, when using at least C# 8.0 (or higher) with .NET Standard 2.1 (or higher) and/or .NET Core 3.0 (or higher), the code from the original question may be written as follows:
private async IAsyncEnumerable<char> TestAsync(string testString)
{
foreach (char c in testString.ToCharArray())
{
// do other work, which may include "await"
yield return c;
}
}