In this example, the method filters the input sequence of strings, yielding only those that start with the letter "A" after asynchronously processing each element.
Aggregating with IAsyncEnumerable
Here’s an example that demonstrates how to use IAsyncEnumerable to calculate the total length of a sequence of strings asynchronously:
public async Task<int> GetTotalLengthAsync(IEnumerable<string> strings) { int totalLength = 0; await foreach (var str in GetStringsAsync(strings)) { totalLength += str.Length; } return totalLength; }
In this example, the method iterates through an asynchronous sequence of strings, calculating the total length of all the strings by adding their lengths asynchronously as they are processed.
Asynchronous projection with IAsyncEnumerable
For example, how you can use projections with IAsyncEnumerable to asynchronously transform a sequence of strings to their uppercase equivalents:
public async IAsyncEnumerable<string> GetUppercaseStringsAsync(IEnumerable<string> strings) { foreach (var str in strings) { await Task.Delay(500); // Simulate async operation yield return await Task.Run(() => str.ToUpper()); } }
In this example, the method takes an asynchronous sequence of strings and projects each string to its uppercase form, returning the transformed values asynchronously.
Transforming a sequence with IAsyncEnumerable
For example, how to use IAsyncEnumerable to transform a sequence of dates into their formatted string representations:
public async IAsyncEnumerable<string> FormatDatesAsync(IEnumerable<DateTime> dates) { foreach (var date in dates) { await Task.Delay(500); // Simulate async operation yield return await Task.Run(() => date.ToString("yyyy-MM-dd")); } }
In this example, the method takes an asynchronous sequence of DateTime
objects and transforms each date into a string formatted as "yyyy-MM-dd", yielding the transformed values asynchronously.
Batch processing with IAsyncEnumerable
For example, how to process items in batches asynchronously using IAsyncEnumerable to handle large sets of strings and process them in chunks:
public static async IAsyncEnumerable<IEnumerable<string>> ProcessStringBatchAsync(IAsyncEnumerable<string> source, int batchSize, CancellationToken cancellationToken = default) { var batch = new List<string>(); await foreach (var str in source) { if (cancellationToken.IsCancellationRequested) yield break; batch.Add(str); if (batch.Count >= batchSize) { yield return batch; batch = new List<string>(); // Clear the batch for the next set } } // Yield the remaining items if they exist if (batch.Count > 0) { yield return batch; } }
In this example, the method processes an asynchronous sequence of strings and groups them into batches of the specified size, yielding each batch asynchronously. If the cancellation token is triggered, it stops processing and returns early. Any remaining items that don't fill an entire batch are yielded at the end.
Buffering with IAsyncEnumerable
For example, how to use buffering with IAsyncEnumerable to process a sequence of numbers more efficiently by buffering a fixed number of items before processing them asynchronously:
public static async IAsyncEnumerable<int> ProcessBufferedNumbersAsync(this IAsyncEnumerable<int> source, int bufferSize, CancellationToken cancellationToken = default) { var buffer = new List<int>(); await foreach (var number in source) { if (cancellationToken.IsCancellationRequested) yield break; buffer.Add(number); if (buffer.Count >= bufferSize) { foreach (var bufferedItem in buffer) { yield return bufferedItem; // Process each item in the buffer } buffer.Clear(); // Clear the buffer for the next set } } // Process any remaining items in the buffer foreach (var remainingItem in buffer) { yield return remainingItem; } }
In this example, the method buffers a sequence of numbers until the buffer reaches the specified size. Once the buffer is full, it processes (yields) the items and clears the buffer for the next batch. If there are any remaining items in the buffer after all items are processed, they are yielded as well.
IAsyncEnumerable offers powerful features for working with asynchronous sequences, including filtering, transforming, and aggregating large datasets. It can be combined with LINQ operators for efficient data manipulation. Additionally, you can handle runtime errors, implement retries, and use logging to ensure errors are managed gracefully during asynchronous operations.