{"id":2221,"date":"2024-12-16T15:42:13","date_gmt":"2024-12-16T15:42:13","guid":{"rendered":"https:\/\/www.w3computing.com\/articles\/?p=2221"},"modified":"2024-12-16T15:42:15","modified_gmt":"2024-12-16T15:42:15","slug":"building-custom-async-enumerables-iasyncenumerable-csharp","status":"publish","type":"post","link":"https:\/\/www.w3computing.com\/articles\/building-custom-async-enumerables-iasyncenumerable-csharp\/","title":{"rendered":"Building Custom Async Enumerables with IAsyncEnumerable in C#"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Asynchronous programming has become a cornerstone of modern software development, and with the advent of <code>IAsyncEnumerable<\/code> in C# 8.0, we gained an elegant way to work with asynchronous data streams. This tutorial will take you through building custom async enumerables step by step. By the end, you will have a solid understanding of how to implement and use <code>IAsyncEnumerable<\/code> effectively.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Introduction to <code>IAsyncEnumerable<\/code><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Before diving into building custom implementations, let\u2019s briefly understand what <code>IAsyncEnumerable<\/code> is and why it\u2019s useful. <code>IAsyncEnumerable<\/code> is an interface that allows iteration over data asynchronously using the <code>await<\/code> keyword. It\u2019s particularly useful when working with streaming data, such as database queries, file reading, or web responses, where data may not be immediately available.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Here\u2019s an example of using <code>IAsyncEnumerable<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">async<\/span> IAsyncEnumerable&lt;<span class=\"hljs-keyword\">int<\/span>&gt; <span class=\"hljs-title\">GetNumbersAsync<\/span>(<span class=\"hljs-params\"><\/span>)<\/span>\n{\n    <span class=\"hljs-keyword\">for<\/span> (<span class=\"hljs-keyword\">int<\/span> i = <span class=\"hljs-number\">1<\/span>; i &lt;= <span class=\"hljs-number\">5<\/span>; i++)\n    {\n        <span class=\"hljs-keyword\">await<\/span> Task.Delay(<span class=\"hljs-number\">1000<\/span>); <span class=\"hljs-comment\">\/\/ Simulate asynchronous work<\/span>\n        <span class=\"hljs-keyword\">yield<\/span> <span class=\"hljs-keyword\">return<\/span> i;\n    }\n}\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">async<\/span> Task <span class=\"hljs-title\">ProcessNumbersAsync<\/span>(<span class=\"hljs-params\"><\/span>)<\/span>\n{\n    <span class=\"hljs-keyword\">await<\/span> <span class=\"hljs-keyword\">foreach<\/span> (<span class=\"hljs-function\"><span class=\"hljs-keyword\">var<\/span> number <span class=\"hljs-keyword\">in<\/span> <span class=\"hljs-title\">GetNumbersAsync<\/span>(<span class=\"hljs-params\"><\/span>))<\/span>\n    {\n        Console.WriteLine(number);\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">In this example, <code>GetNumbersAsync<\/code> yields numbers asynchronously, and <code>ProcessNumbersAsync<\/code> consumes them using <code>await foreach<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Core Concepts of <code>IAsyncEnumerable<\/code><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">To effectively implement <code>IAsyncEnumerable<\/code>, you need to understand the following key concepts:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong><code>IAsyncEnumerable&lt;T><\/code><\/strong>: The main interface representing an asynchronous stream.<\/li>\n\n\n\n<li><strong><code>IAsyncEnumerator&lt;T><\/code><\/strong>: Represents the enumerator used to iterate asynchronously over the elements.<\/li>\n\n\n\n<li><strong><code>MoveNextAsync<\/code><\/strong>: A method of <code>IAsyncEnumerator&lt;T><\/code> that advances to the next element asynchronously.<\/li>\n\n\n\n<li><strong><code>Current<\/code><\/strong>: A property of <code>IAsyncEnumerator&lt;T><\/code> that gets the current element in the collection.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">With these basics in mind, let\u2019s start building custom async enumerables.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 1: Creating a Custom Async Enumerable Class<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">We\u2019ll begin by implementing a simple custom async enumerable that produces a sequence of numbers asynchronously. For this, we\u2019ll create a class that implements <code>IAsyncEnumerable&lt;T&gt;<\/code> and <code>IAsyncEnumerator&lt;T&gt;<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Implementing <code>IAsyncEnumerable&lt;T&gt;<\/code><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The first step is to implement the <code>IAsyncEnumerable&lt;T&gt;<\/code> interface. This requires defining a method <code>GetAsyncEnumerator<\/code>, which returns an instance of <code>IAsyncEnumerator&lt;T&gt;<\/code>.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">AsyncNumberSequence<\/span> : <span class=\"hljs-title\">IAsyncEnumerable<\/span>&lt;<span class=\"hljs-title\">int<\/span>&gt;\n{\n    <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">readonly<\/span> <span class=\"hljs-keyword\">int<\/span> _start;\n    <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">readonly<\/span> <span class=\"hljs-keyword\">int<\/span> _count;\n\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-title\">AsyncNumberSequence<\/span>(<span class=\"hljs-params\"><span class=\"hljs-keyword\">int<\/span> start, <span class=\"hljs-keyword\">int<\/span> count<\/span>)<\/span>\n    {\n        _start = start;\n        _count = count;\n    }\n\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> IAsyncEnumerator&lt;<span class=\"hljs-keyword\">int<\/span>&gt; <span class=\"hljs-title\">GetAsyncEnumerator<\/span>(<span class=\"hljs-params\">CancellationToken cancellationToken = <span class=\"hljs-keyword\">default<\/span><\/span>)<\/span>\n    {\n        <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-keyword\">new<\/span> AsyncNumberEnumerator(_start, _count);\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">In this class, the constructor takes a starting number and a count. The <code>GetAsyncEnumerator<\/code> method returns an instance of a custom enumerator class that we\u2019ll define next.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Implementing <code>IAsyncEnumerator&lt;T&gt;<\/code><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Next, we need to implement the <code>IAsyncEnumerator&lt;T&gt;<\/code> interface. This involves defining the <code>MoveNextAsync<\/code> method and the <code>Current<\/code> property.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">AsyncNumberEnumerator<\/span> : <span class=\"hljs-title\">IAsyncEnumerator<\/span>&lt;<span class=\"hljs-title\">int<\/span>&gt;\n{\n    <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">readonly<\/span> <span class=\"hljs-keyword\">int<\/span> _start;\n    <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">readonly<\/span> <span class=\"hljs-keyword\">int<\/span> _count;\n    <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">int<\/span> _currentIndex;\n\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-title\">AsyncNumberEnumerator<\/span>(<span class=\"hljs-params\"><span class=\"hljs-keyword\">int<\/span> start, <span class=\"hljs-keyword\">int<\/span> count<\/span>)<\/span>\n    {\n        _start = start;\n        _count = count;\n        _currentIndex = <span class=\"hljs-number\">-1<\/span>;\n    }\n\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">int<\/span> Current { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">set<\/span>; }\n\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">async<\/span> ValueTask&lt;<span class=\"hljs-keyword\">bool<\/span>&gt; <span class=\"hljs-title\">MoveNextAsync<\/span>(<span class=\"hljs-params\"><\/span>)<\/span>\n    {\n        <span class=\"hljs-keyword\">await<\/span> Task.Delay(<span class=\"hljs-number\">500<\/span>); <span class=\"hljs-comment\">\/\/ Simulate asynchronous work<\/span>\n\n        <span class=\"hljs-keyword\">if<\/span> (_currentIndex + <span class=\"hljs-number\">1<\/span> &lt; _count)\n        {\n            _currentIndex++;\n            Current = _start + _currentIndex;\n            <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-literal\">true<\/span>;\n        }\n\n        <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-literal\">false<\/span>;\n    }\n\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> ValueTask <span class=\"hljs-title\">DisposeAsync<\/span>(<span class=\"hljs-params\"><\/span>)<\/span>\n    {\n        <span class=\"hljs-comment\">\/\/ Clean up resources if necessary<\/span>\n        <span class=\"hljs-keyword\">return<\/span> ValueTask.CompletedTask;\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The <code>MoveNextAsync<\/code> method advances the enumerator to the next item in the sequence, simulating asynchronous work with <code>Task.Delay<\/code>. The <code>DisposeAsync<\/code> method is included for cleanup, although it\u2019s not required in this simple example.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 2: Consuming the Custom Async Enumerable<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">With the custom async enumerable and enumerator in place, let\u2019s write code to consume it using <code>await foreach<\/code>.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">async<\/span> Task <span class=\"hljs-title\">RunAsync<\/span>(<span class=\"hljs-params\"><\/span>)<\/span>\n{\n    <span class=\"hljs-keyword\">var<\/span> numbers = <span class=\"hljs-keyword\">new<\/span> AsyncNumberSequence(<span class=\"hljs-number\">1<\/span>, <span class=\"hljs-number\">10<\/span>);\n\n    <span class=\"hljs-keyword\">await<\/span> <span class=\"hljs-keyword\">foreach<\/span> (<span class=\"hljs-keyword\">var<\/span> number <span class=\"hljs-keyword\">in<\/span> numbers)\n    {\n        Console.WriteLine(number);\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">This will output numbers from 1 to 10 with a delay of 500 milliseconds between each.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 3: Adding Cancellation Support<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Asynchronous operations should respect cancellation to improve responsiveness and resource management. To support cancellation, we use the <code>CancellationToken<\/code> passed to <code>GetAsyncEnumerator<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Updating the Enumerator<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Modify the <code>AsyncNumberEnumerator<\/code> to check the cancellation token in the <code>MoveNextAsync<\/code> method:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">AsyncNumberEnumerator<\/span> : <span class=\"hljs-title\">IAsyncEnumerator<\/span>&lt;<span class=\"hljs-title\">int<\/span>&gt;\n{\n    <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">readonly<\/span> <span class=\"hljs-keyword\">int<\/span> _start;\n    <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">readonly<\/span> <span class=\"hljs-keyword\">int<\/span> _count;\n    <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">readonly<\/span> CancellationToken _cancellationToken;\n    <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">int<\/span> _currentIndex;\n\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-title\">AsyncNumberEnumerator<\/span>(<span class=\"hljs-params\"><span class=\"hljs-keyword\">int<\/span> start, <span class=\"hljs-keyword\">int<\/span> count, CancellationToken cancellationToken<\/span>)<\/span>\n    {\n        _start = start;\n        _count = count;\n        _cancellationToken = cancellationToken;\n        _currentIndex = <span class=\"hljs-number\">-1<\/span>;\n    }\n\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">int<\/span> Current { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">set<\/span>; }\n\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">async<\/span> ValueTask&lt;<span class=\"hljs-keyword\">bool<\/span>&gt; <span class=\"hljs-title\">MoveNextAsync<\/span>(<span class=\"hljs-params\"><\/span>)<\/span>\n    {\n        _cancellationToken.ThrowIfCancellationRequested();\n        <span class=\"hljs-keyword\">await<\/span> Task.Delay(<span class=\"hljs-number\">500<\/span>, _cancellationToken); <span class=\"hljs-comment\">\/\/ Support cancellation<\/span>\n\n        <span class=\"hljs-keyword\">if<\/span> (_currentIndex + <span class=\"hljs-number\">1<\/span> &lt; _count)\n        {\n            _currentIndex++;\n            Current = _start + _currentIndex;\n            <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-literal\">true<\/span>;\n        }\n\n        <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-literal\">false<\/span>;\n    }\n\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> ValueTask <span class=\"hljs-title\">DisposeAsync<\/span>(<span class=\"hljs-params\"><\/span>)<\/span>\n    {\n        <span class=\"hljs-keyword\">return<\/span> ValueTask.CompletedTask;\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">Passing the Cancellation Token<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Update <code>GetAsyncEnumerator<\/code> to pass the cancellation token:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> IAsyncEnumerator&lt;<span class=\"hljs-keyword\">int<\/span>&gt; <span class=\"hljs-title\">GetAsyncEnumerator<\/span>(<span class=\"hljs-params\">CancellationToken cancellationToken = <span class=\"hljs-keyword\">default<\/span><\/span>)<\/span>\n{\n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-keyword\">new<\/span> AsyncNumberEnumerator(_start, _count, cancellationToken);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">Using Cancellation in Consumer Code<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">You can now use a cancellation token in the consuming code:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">async<\/span> Task <span class=\"hljs-title\">RunWithCancellationAsync<\/span>(<span class=\"hljs-params\">CancellationToken cancellationToken<\/span>)<\/span>\n{\n    <span class=\"hljs-keyword\">var<\/span> numbers = <span class=\"hljs-keyword\">new<\/span> AsyncNumberSequence(<span class=\"hljs-number\">1<\/span>, <span class=\"hljs-number\">10<\/span>);\n\n    <span class=\"hljs-keyword\">try<\/span>\n    {\n        <span class=\"hljs-keyword\">await<\/span> <span class=\"hljs-keyword\">foreach<\/span> (<span class=\"hljs-keyword\">var<\/span> number <span class=\"hljs-keyword\">in<\/span> numbers.WithCancellation(cancellationToken))\n        {\n            Console.WriteLine(number);\n        }\n    }\n    <span class=\"hljs-keyword\">catch<\/span> (OperationCanceledException)\n    {\n        Console.WriteLine(<span class=\"hljs-string\">\"Operation was canceled.\"<\/span>);\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Step 4: Handling Exceptions Gracefully<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Errors can occur during asynchronous iteration. To handle exceptions, wrap the logic in <code>MoveNextAsync<\/code> with try-catch blocks.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">async<\/span> ValueTask&lt;<span class=\"hljs-keyword\">bool<\/span>&gt; <span class=\"hljs-title\">MoveNextAsync<\/span>(<span class=\"hljs-params\"><\/span>)<\/span>\n{\n    <span class=\"hljs-keyword\">try<\/span>\n    {\n        _cancellationToken.ThrowIfCancellationRequested();\n        <span class=\"hljs-keyword\">await<\/span> Task.Delay(<span class=\"hljs-number\">500<\/span>, _cancellationToken);\n\n        <span class=\"hljs-keyword\">if<\/span> (_currentIndex + <span class=\"hljs-number\">1<\/span> &lt; _count)\n        {\n            _currentIndex++;\n            Current = _start + _currentIndex;\n            <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-literal\">true<\/span>;\n        }\n\n        <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-literal\">false<\/span>;\n    }\n    <span class=\"hljs-keyword\">catch<\/span> (Exception ex)\n    {\n        Console.WriteLine(<span class=\"hljs-string\">$\"Error: <span class=\"hljs-subst\">{ex.Message}<\/span>\"<\/span>);\n        <span class=\"hljs-keyword\">throw<\/span>;\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Step 5: Advanced Scenarios<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Streaming Data from APIs<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">You can use <code>IAsyncEnumerable<\/code> to stream data from APIs or other sources. For example, fetching data from a paginated API:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">async<\/span> IAsyncEnumerable&lt;<span class=\"hljs-keyword\">string<\/span>&gt; <span class=\"hljs-title\">FetchDataAsync<\/span>(<span class=\"hljs-params\"><\/span>)<\/span>\n{\n    <span class=\"hljs-keyword\">int<\/span> page = <span class=\"hljs-number\">1<\/span>;\n\n    <span class=\"hljs-keyword\">while<\/span> (<span class=\"hljs-literal\">true<\/span>)\n    {\n        <span class=\"hljs-keyword\">var<\/span> data = <span class=\"hljs-keyword\">await<\/span> FetchPageAsync(page++);\n\n        <span class=\"hljs-keyword\">if<\/span> (data == <span class=\"hljs-literal\">null<\/span> || !data.Any())\n            <span class=\"hljs-keyword\">yield<\/span> <span class=\"hljs-keyword\">break<\/span>;\n\n        <span class=\"hljs-keyword\">foreach<\/span> (<span class=\"hljs-keyword\">var<\/span> item <span class=\"hljs-keyword\">in<\/span> data)\n        {\n            <span class=\"hljs-keyword\">yield<\/span> <span class=\"hljs-keyword\">return<\/span> item;\n        }\n    }\n}\n\n<span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">async<\/span> Task&lt;List&lt;<span class=\"hljs-keyword\">string<\/span>&gt;&gt; FetchPageAsync(<span class=\"hljs-keyword\">int<\/span> page)\n{\n    <span class=\"hljs-comment\">\/\/ Simulate fetching data<\/span>\n    <span class=\"hljs-keyword\">await<\/span> Task.Delay(<span class=\"hljs-number\">1000<\/span>);\n    <span class=\"hljs-keyword\">return<\/span> page &lt;= <span class=\"hljs-number\">3<\/span> ? <span class=\"hljs-keyword\">new<\/span> List&lt;<span class=\"hljs-keyword\">string<\/span>&gt; { <span class=\"hljs-string\">\"Item1\"<\/span>, <span class=\"hljs-string\">\"Item2\"<\/span> } : <span class=\"hljs-literal\">null<\/span>;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">Processing Large Files<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><code>IAsyncEnumerable<\/code> is useful for processing large files line by line:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">async<\/span> IAsyncEnumerable&lt;<span class=\"hljs-keyword\">string<\/span>&gt; <span class=\"hljs-title\">ReadLinesAsync<\/span>(<span class=\"hljs-params\"><span class=\"hljs-keyword\">string<\/span> filePath<\/span>)<\/span>\n{\n    <span class=\"hljs-keyword\">using<\/span> <span class=\"hljs-keyword\">var<\/span> reader = <span class=\"hljs-keyword\">new<\/span> StreamReader(filePath);\n    <span class=\"hljs-keyword\">while<\/span> (!reader.EndOfStream)\n    {\n        <span class=\"hljs-keyword\">yield<\/span> <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-keyword\">await<\/span> reader.ReadLineAsync();\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">In this tutorial, we explored the step-by-step process of building custom async enumerables using <code>IAsyncEnumerable<\/code> in C#. We started with the basics, added cancellation support, and handled exceptions. Finally, we looked at advanced scenarios like streaming data from APIs and processing large files.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Asynchronous programming has become a cornerstone of modern software development, and with the advent of IAsyncEnumerable in C# 8.0, we gained an elegant way to work with asynchronous data streams. This tutorial will take you through building custom async enumerables step by step. By the end, you will have a solid understanding of how to [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_genesis_hide_title":false,"_genesis_hide_breadcrumbs":false,"_genesis_hide_singular_image":false,"_genesis_hide_footer_widgets":false,"_genesis_custom_body_class":"","_genesis_custom_post_class":"","_genesis_layout":"","_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[8,4],"tags":[],"class_list":["post-2221","post","type-post","status-publish","format-standard","category-csharp","category-programming-languages","entry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.6 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Building Custom Async Enumerables with IAsyncEnumerable in C#<\/title>\n<meta name=\"description\" content=\"IAsyncEnumerable is an interface that allows iteration over data asynchronously using the await keyword. It\u2019s particularly useful when working with streaming data\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.w3computing.com\/articles\/building-custom-async-enumerables-iasyncenumerable-csharp\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Building Custom Async Enumerables with IAsyncEnumerable in C#\" \/>\n<meta property=\"og:description\" content=\"IAsyncEnumerable is an interface that allows iteration over data asynchronously using the await keyword. It\u2019s particularly useful when working with streaming data\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.w3computing.com\/articles\/building-custom-async-enumerables-iasyncenumerable-csharp\/\" \/>\n<meta property=\"article:published_time\" content=\"2024-12-16T15:42:13+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-12-16T15:42:15+00:00\" \/>\n<meta name=\"author\" content=\"w3compadmin\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"w3compadmin\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"3 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"TechArticle\",\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/building-custom-async-enumerables-iasyncenumerable-csharp\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/building-custom-async-enumerables-iasyncenumerable-csharp\\\/\"},\"author\":{\"name\":\"w3compadmin\",\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/#\\\/schema\\\/person\\\/a550b3e20d78bb4f79b7c6b7b53f0561\"},\"headline\":\"Building Custom Async Enumerables with IAsyncEnumerable in C#\",\"datePublished\":\"2024-12-16T15:42:13+00:00\",\"dateModified\":\"2024-12-16T15:42:15+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/building-custom-async-enumerables-iasyncenumerable-csharp\\\/\"},\"wordCount\":526,\"articleSection\":[\"C#\",\"Programming Languages\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/building-custom-async-enumerables-iasyncenumerable-csharp\\\/\",\"url\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/building-custom-async-enumerables-iasyncenumerable-csharp\\\/\",\"name\":\"Building Custom Async Enumerables with IAsyncEnumerable in C#\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/#website\"},\"datePublished\":\"2024-12-16T15:42:13+00:00\",\"dateModified\":\"2024-12-16T15:42:15+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/#\\\/schema\\\/person\\\/a550b3e20d78bb4f79b7c6b7b53f0561\"},\"description\":\"IAsyncEnumerable is an interface that allows iteration over data asynchronously using the await keyword. It\u2019s particularly useful when working with streaming data\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/building-custom-async-enumerables-iasyncenumerable-csharp\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/building-custom-async-enumerables-iasyncenumerable-csharp\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/building-custom-async-enumerables-iasyncenumerable-csharp\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Articles Home\",\"item\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Programming Languages\",\"item\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/programming-languages\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"C#\",\"item\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/programming-languages\\\/csharp\\\/\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"Building Custom Async Enumerables with IAsyncEnumerable in C#\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/#website\",\"url\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/\",\"name\":\"Developer Articles Hub\",\"description\":\"\",\"alternateName\":\"Developer Articles\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/#\\\/schema\\\/person\\\/a550b3e20d78bb4f79b7c6b7b53f0561\",\"name\":\"w3compadmin\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/wp-content\\\/litespeed\\\/avatar\\\/bd481d404e42caa2763662a3bfe825f8.jpg?ver=1780141266\",\"url\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/wp-content\\\/litespeed\\\/avatar\\\/bd481d404e42caa2763662a3bfe825f8.jpg?ver=1780141266\",\"contentUrl\":\"https:\\\/\\\/www.w3computing.com\\\/articles\\\/wp-content\\\/litespeed\\\/avatar\\\/bd481d404e42caa2763662a3bfe825f8.jpg?ver=1780141266\",\"caption\":\"w3compadmin\"},\"sameAs\":[\"http:\\\/\\\/w3computing.com\\\/articles\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Building Custom Async Enumerables with IAsyncEnumerable in C#","description":"IAsyncEnumerable is an interface that allows iteration over data asynchronously using the await keyword. It\u2019s particularly useful when working with streaming data","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.w3computing.com\/articles\/building-custom-async-enumerables-iasyncenumerable-csharp\/","og_locale":"en_US","og_type":"article","og_title":"Building Custom Async Enumerables with IAsyncEnumerable in C#","og_description":"IAsyncEnumerable is an interface that allows iteration over data asynchronously using the await keyword. It\u2019s particularly useful when working with streaming data","og_url":"https:\/\/www.w3computing.com\/articles\/building-custom-async-enumerables-iasyncenumerable-csharp\/","article_published_time":"2024-12-16T15:42:13+00:00","article_modified_time":"2024-12-16T15:42:15+00:00","author":"w3compadmin","twitter_card":"summary_large_image","twitter_misc":{"Written by":"w3compadmin","Est. reading time":"3 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"TechArticle","@id":"https:\/\/www.w3computing.com\/articles\/building-custom-async-enumerables-iasyncenumerable-csharp\/#article","isPartOf":{"@id":"https:\/\/www.w3computing.com\/articles\/building-custom-async-enumerables-iasyncenumerable-csharp\/"},"author":{"name":"w3compadmin","@id":"https:\/\/www.w3computing.com\/articles\/#\/schema\/person\/a550b3e20d78bb4f79b7c6b7b53f0561"},"headline":"Building Custom Async Enumerables with IAsyncEnumerable in C#","datePublished":"2024-12-16T15:42:13+00:00","dateModified":"2024-12-16T15:42:15+00:00","mainEntityOfPage":{"@id":"https:\/\/www.w3computing.com\/articles\/building-custom-async-enumerables-iasyncenumerable-csharp\/"},"wordCount":526,"articleSection":["C#","Programming Languages"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/www.w3computing.com\/articles\/building-custom-async-enumerables-iasyncenumerable-csharp\/","url":"https:\/\/www.w3computing.com\/articles\/building-custom-async-enumerables-iasyncenumerable-csharp\/","name":"Building Custom Async Enumerables with IAsyncEnumerable in C#","isPartOf":{"@id":"https:\/\/www.w3computing.com\/articles\/#website"},"datePublished":"2024-12-16T15:42:13+00:00","dateModified":"2024-12-16T15:42:15+00:00","author":{"@id":"https:\/\/www.w3computing.com\/articles\/#\/schema\/person\/a550b3e20d78bb4f79b7c6b7b53f0561"},"description":"IAsyncEnumerable is an interface that allows iteration over data asynchronously using the await keyword. It\u2019s particularly useful when working with streaming data","breadcrumb":{"@id":"https:\/\/www.w3computing.com\/articles\/building-custom-async-enumerables-iasyncenumerable-csharp\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.w3computing.com\/articles\/building-custom-async-enumerables-iasyncenumerable-csharp\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.w3computing.com\/articles\/building-custom-async-enumerables-iasyncenumerable-csharp\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Articles Home","item":"https:\/\/www.w3computing.com\/articles\/"},{"@type":"ListItem","position":2,"name":"Programming Languages","item":"https:\/\/www.w3computing.com\/articles\/programming-languages\/"},{"@type":"ListItem","position":3,"name":"C#","item":"https:\/\/www.w3computing.com\/articles\/programming-languages\/csharp\/"},{"@type":"ListItem","position":4,"name":"Building Custom Async Enumerables with IAsyncEnumerable in C#"}]},{"@type":"WebSite","@id":"https:\/\/www.w3computing.com\/articles\/#website","url":"https:\/\/www.w3computing.com\/articles\/","name":"Developer Articles Hub","description":"","alternateName":"Developer Articles","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.w3computing.com\/articles\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.w3computing.com\/articles\/#\/schema\/person\/a550b3e20d78bb4f79b7c6b7b53f0561","name":"w3compadmin","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.w3computing.com\/articles\/wp-content\/litespeed\/avatar\/bd481d404e42caa2763662a3bfe825f8.jpg?ver=1780141266","url":"https:\/\/www.w3computing.com\/articles\/wp-content\/litespeed\/avatar\/bd481d404e42caa2763662a3bfe825f8.jpg?ver=1780141266","contentUrl":"https:\/\/www.w3computing.com\/articles\/wp-content\/litespeed\/avatar\/bd481d404e42caa2763662a3bfe825f8.jpg?ver=1780141266","caption":"w3compadmin"},"sameAs":["http:\/\/w3computing.com\/articles"]}]}},"featured_image_src":null,"featured_image_src_square":null,"author_info":{"display_name":"w3compadmin","author_link":"https:\/\/www.w3computing.com\/articles\/author\/w3compadmin\/"},"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/posts\/2221","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/comments?post=2221"}],"version-history":[{"count":1,"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/posts\/2221\/revisions"}],"predecessor-version":[{"id":2222,"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/posts\/2221\/revisions\/2222"}],"wp:attachment":[{"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/media?parent=2221"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/categories?post=2221"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.w3computing.com\/articles\/wp-json\/wp\/v2\/tags?post=2221"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}