This is part 8 in a series of articles.
In earlier versions of C# you could return an IEnumerable<T> from a method, for example to be consumed by a foreach loop.
The following example shows a method from a WPF app that returns 3 web pages as string content:
public static IEnumerable<string> LoadWebPages()
{
using (var client = new HttpClient())
{
yield return client.GetStringAsync("http://dontcodetired.com/blog/post/ICYMI-C-8-New-Features-Switch-Expressions").Result;
yield return client.GetStringAsync("http://dontcodetired.com/blog/post/ICYMI-C-8-New-Features-Write-Less-Code-with-Using-Declarations").Result;
yield return client.GetStringAsync("http://dontcodetired.com/blog/post/ICYMI-C-8-New-Features-Write-Less-Code-with-Using-Declarations").Result;
}
}
This method could be used in a click event handler in the WPF app (or via MVVM etc.):
private void NotAsync_Click(object sender, RoutedEventArgs e)
{
foreach (var page in WebPageLoader.LoadWebPages())
{
var titleIndex = page.IndexOf("<title>");
txt.Text += Environment.NewLine + $"Got page: {page.Substring(titleIndex, 110)}";
}
}
When you run the app and click the button, the 3 web pages will be loaded and added to the content of the <TextBlock x:Name="txt"></TextBlock>
While loading the 3 web pages and looping through the foreach loop however, the app will be unresponsive until all 3 pages have been returned in the foreach loop.
C# 8 introduced the ability to use the IAsyncEnumerable<T> interface to iterate items asynchronously.
The “asynchronous streams” feature of C# 8 should not be confused with the streams in the System.IO namespace.
The LoadWebPages method can be re-written in C# 8 as:
public static async IAsyncEnumerable<string> LoadWebPagesAsync()
{
using var client = new HttpClient();
yield return await client.GetStringAsync("http://dontcodetired.com/blog/post/ICYMI-C-8-New-Features-Switch-Expressions");
yield return await client.GetStringAsync("http://dontcodetired.com/blog/post/ICYMI-C-8-New-Features-Write-Less-Code-with-Using-Declarations");
yield return await client.GetStringAsync("http://dontcodetired.com/blog/post/ICYMI-C-8-New-Features-Simplify-If-Statements-with-Property-Pattern-Matching");
}
And to consume this version:
private async void Async_Click(object sender, RoutedEventArgs e)
{
await foreach (var page in WebPageLoader.LoadWebPagesAsync())
{
var titleIndex = page.IndexOf("<title>");
txt.Text += Environment.NewLine + $"Got page: {page.Substring(titleIndex, 110)}";
}
}
Now when the <Button Content="Async" x:Name="Async" Click="Async_Click"></Button> button is clicked, the 3 webpages will be enumerated in an async manner meaning that the UI will remain responsive.
The IAsyncEnumerable<T> interface also provides for cancellation: IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default);
If you want to fill in the gaps in your C# knowledge be sure to check out my C# Tips and Traps training course from Pluralsight – get started with a free trial.
SHARE: