Skip to content

v2.0.0

Choose a tag to compare

@i3arnon i3arnon released this 17 Jan 21:04
· 25 commits to main since this release
df8cb69

NuGet

Overview

This release modernizes MoreAsyncLINQ to align with System.Linq.AsyncEnumerable conventions introduced in .NET 10, updates target frameworks, and introduces a consistent API pattern for async delegates.

Breaking Changes

Target Framework Updates

  • Changed: net461 → net462
  • Added: net8.0, net9.0, net10.0

PartitionAsync Return Type Changed

PartitionAsync now returns IEnumerable<TSource> instead of IAsyncEnumerable<TSource> in its tuple result:

Before (v1.0.0):

ValueTask<(IAsyncEnumerable<TSource> True, IAsyncEnumerable<TSource> False)> PartitionAsync(...)

After (v2.0.0):

ValueTask<(IEnumerable<TSource> True, IEnumerable<TSource> False)> PartitionAsync(...)

Migration: Since PartitionAsync is a materializing operator that consumes the entire source sequence, the partition results are now returned as IEnumerable<T>. If you need async enumeration, use ToAsyncEnumerable() on the results.

Async Delegate Signature Changes

All async delegate overloads now require a CancellationToken parameter. The legacy *Await and *AwaitAsync methods that accept Func<T, ValueTask<TResult>> are now marked as [Obsolete].

Before (v1.0.0):

source.SelectAwait(async x => await ProcessAsync(x))

After (v2.0.0):

source.Select(async (x, cancellationToken) => await ProcessAsync(x, cancellationToken))

This affects all operators with async overloads including:

  • Cartesian
  • Choose
  • ExceptBy
  • FillBackward
  • FillForward
  • From
  • GenerateByIndex
  • Maxima / Minima
  • OrderBy
  • Pad / PadStart
  • Pairwise
  • Partition
  • ZipLongest
  • And many more...

Hidden Operators

The following operators are now hidden (not removed) since they are included in System.Linq.AsyncEnumerable:

  • CountBy
  • DistinctBy
  • Index
  • SkipLast
  • TakeLast
  • ToDictionary

These methods remain available for backward compatibility but will not appear in IntelliSense. Prefer using the built-in System.Linq.AsyncEnumerable versions.

Removed ConfigureAwait(false)

Following .NET runtime conventions, ConfigureAwait(false) calls have been removed throughout the library, matching the behavior of System.Linq.AsyncEnumerable.

New Features

Maxima and Minima Operators

New operators that return all maximal/minimal elements with modern async delegate signatures:

// Sync selector
var maxElements = await source.Maxima(x => x.Score).ToListAsync();

// Async selector with CancellationToken
var minElements = await source.Minima(
    async (x, ct) => await GetScoreAsync(x, ct),
    cancellationToken
).ToListAsync();

MaxBy and MinBy continue to work for sync selectors but their *Await variants are now obsolete. Use Maxima and Minima for async scenarios.

Migration Guide

1. Update async delegate calls

Replace legacy async delegates with the new CancellationToken signature:

// Before
items.WhereAwait(async x => await CheckAsync(x))

// After  
items.Where(async (x, ct) => await CheckAsync(x, ct))

2. Update PartitionAsync usage

If you were iterating the partition results asynchronously:

// Before
var (trueItems, falseItems) = await source.PartitionAsync(predicate);
await foreach (var item in trueItems) { ... }

// After
var (trueItems, falseItems) = await source.PartitionAsync(predicate);
foreach (var item in trueItems) { ... }  // Sync iteration
// Or if you need async:
await foreach (var item in trueItems.ToAsyncEnumerable()) { ... }

3. Use built-in operators when available

For .NET 10+ projects, prefer the built-in System.Linq.AsyncEnumerable versions of:

  • CountBy
  • DistinctBy
  • Index
  • SkipLast
  • TakeLast
  • ToDictionary

Full Changelog: v1.0.0...v2.0.0