async-enumerable.md

July 3, 2026 ¡ View on GitHub

Async Enumerable

Specifying IAsyncEnumerable<T> as the injection type allows instances of all bindings implementing type T to be injected in an asynchronous-lazy manner - the instances will be provided one at a time, in an order corresponding to the sequence of the bindings.

using Shouldly;
using Pure.DI;

DI.Setup(nameof(Composition))
    .Bind<IHealthCheck>().To<MemoryCheck>()
    .Bind<IHealthCheck>("External").To<ExternalServiceCheck>()
    .Bind<IHealthService>().To<HealthService>()

    // Composition root
    .Root<IHealthService>("HealthService");

var composition = new Composition();
var healthService = composition.HealthService;
var checks = await healthService.GetChecksAsync();

checks[0].ShouldBeOfType<MemoryCheck>();
checks[1].ShouldBeOfType<ExternalServiceCheck>();

interface IHealthCheck;

class MemoryCheck : IHealthCheck;

class ExternalServiceCheck : IHealthCheck;

interface IHealthService
{
    Task<IReadOnlyList<IHealthCheck>> GetChecksAsync();
}

class HealthService(IAsyncEnumerable<IHealthCheck> checks) : IHealthService
{
    public async Task<IReadOnlyList<IHealthCheck>> GetChecksAsync()
    {
        var results = new List<IHealthCheck>();
        await foreach (var check in checks)
        {
            results.Add(check);
        }

        return results;
    }
}
Running this code sample locally
dotnet --list-sdk
  • Create a net10.0 (or later) console application
dotnet new console -n Sample
dotnet add package Pure.DI
dotnet add package Shouldly
  • Copy the example code into the Program.cs file

You are ready to run the example 🚀

dotnet run

Note

IAsyncEnumerable provides efficient lazy enumeration for scenarios where you need to process many instances without loading them all into memory at once.

The following partial class will be generated
partial class Composition
{
  public IHealthService HealthService
  {
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    get
    {
      [MethodImpl(MethodImplOptions.AggressiveInlining)]
      async IAsyncEnumerable<IHealthCheck> EnumerationOf_transientIAsyncEnumerableIHealthCheck()
      {
        yield return new MemoryCheck();
        yield return new ExternalServiceCheck();
        await Task.CompletedTask;
      }

      return new HealthService(EnumerationOf_transientIAsyncEnumerableIHealthCheck());
    }
  }
}

Class diagram:

---
 config:
  class:
   hideEmptyMembersBox: true
---
classDiagram
	MemoryCheck --|> IHealthCheck
	ExternalServiceCheck --|> IHealthCheck : "External"
	HealthService --|> IHealthService
	Composition ..> HealthService : IHealthService HealthService
	HealthService *-- IAsyncEnumerableᐸIHealthCheckᐳ : IAsyncEnumerableᐸIHealthCheckᐳ
	IAsyncEnumerableᐸIHealthCheckᐳ *-- MemoryCheck : IHealthCheck
	IAsyncEnumerableᐸIHealthCheckᐳ *-- ExternalServiceCheck : "External" IHealthCheck
	namespace Pure.DI.UsageTests.BCL.AsyncEnumerableScenario {
		class Composition {
		<<partial>>
		+IHealthService HealthService
		}
		class ExternalServiceCheck {
				<<class>>
			+ExternalServiceCheck()
		}
		class HealthService {
				<<class>>
			+HealthService(IAsyncEnumerableᐸIHealthCheckᐳ checks)
		}
		class IHealthCheck {
			<<interface>>
		}
		class IHealthService {
			<<interface>>
		}
		class MemoryCheck {
				<<class>>
			+MemoryCheck()
		}
	}
	namespace System.Collections.Generic {
		class IAsyncEnumerableᐸIHealthCheckᐳ {
				<<interface>>
		}
	}

See also: