ZipParams is a small .NET 9 library that extends the standard LINQ zip operation to support any number of collections with the same element type.
The project provides synchronous and asynchronous extension methods for IEnumerable<T> and IAsyncEnumerable<T>.
- Accepts additional collections through
params - Supports any number of collections, including zero
- Produces one read-only row for each group of matching elements
- Stops when the shortest input collection ends
- Evaluates collections lazily
- Disposes every created enumerator
- Propagates cancellation to asynchronous enumerators
ZipParams.sln
ZipParams/
EnumerableExtensions.cs
ZipParams.csproj
ZipParamsTests/
EnumerableExtensionsTests.cs
ZipParamsTests.csproj
using ZipParams;
IEnumerable<int> first = [1, 2, 3];
IEnumerable<int> second = [10, 20, 30];
IEnumerable<int> third = [100, 200, 300];
var rows = first.Zip(second, third);
foreach (var row in rows)
{
Console.WriteLine(string.Join(", ", row));
}The resulting rows are [1, 10, 100], [2, 20, 200], and [3, 30, 300].
Calling Zip without additional collections produces rows containing only the elements from the source collection.
using ZipParams;
IAsyncEnumerable<int> first = GetFirstAsync();
IAsyncEnumerable<int> second = GetSecondAsync();
IAsyncEnumerable<int> third = GetThirdAsync();
await foreach (var row in first.ZipAsync(second, third))
{
Console.WriteLine(string.Join(", ", row));
}ZipAsync follows the same shortest-collection rule and supports cancellation through normal asynchronous enumeration.
Run the complete test suite from the repository root:
dotnet test ZipParams.slnThe test project uses xUnit and FluentAssertions. It covers empty params input, multiple equal-length collections, different-length collections, synchronous disposal, and asynchronous disposal.