Skip to content

Releases: i3arnon/MoreAsyncLINQ

v3.0.0

Choose a tag to compare

@i3arnon i3arnon released this 09 Feb 14:25
e021b24

NuGet

What's Changed

  • Hide Obsolete overloads in #58
  • Tests | Choose in #61
  • Tests | Partition in #62
  • Generators | Aggregate in #65
  • Generators | Cartesian in #67
  • Generators | Fold in #69
  • Use ArrayPool in #70

Breaking Changes

Obsolete overloads (i.e. ChooseAwait) are no longer extension methods.

Please either:

  • Switch to the non-obsolete overloads respecting the new .NET 10.0 async LINQ pattern.
  • Use as static method invocation (MoreAsyncEnumerable.ChooseAwait(..).

Full Changelog: v2.2.0...v3.0.0

v2.2.0

Choose a tag to compare

@i3arnon i3arnon released this 31 Jan 09:01
7e4d889

NuGet

Operators Added:

  • GroupAdjacent in #47
  • ForEach in #54
  • FullGroupJoin in #48
  • Duplicates in #49
  • SkipLastWhile in #50

Full Changelog: v2.0.0...v2.2.0

v2.0.0

Choose a tag to compare

@i3arnon i3arnon released this 17 Jan 21:04
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

v1.0.0

Choose a tag to compare

@i3arnon i3arnon released this 14 Jan 09:14
8bf705c

NuGet

Breaking Changes

Dependency Migration: System.Linq.Async → System.Linq.AsyncEnumerable

This release removes the dependency on System.Linq.Async and replaces it with the new System.Linq.AsyncEnumerable package released in .NET 10.0.

What this means for you:

  • If you're upgrading from a previous version, you'll need to update your using directives
  • The new System.Linq.AsyncEnumerable is the official Microsoft implementation shipping with .NET 10
  • For more details, see: .NET 10 AsyncEnumerable Breaking Change

IAsyncGrouping → IGrouping in Partition Methods

The following methods now use System.Linq.IGrouping<TKey, TElement> instead of System.Linq.IAsyncGrouping<TKey, TElement>:

  • PartitionAsync<TSource, TResult>(IAsyncEnumerable<IGrouping<bool, TSource>>, ...)
  • PartitionAsync<TSource, TResult>(IAsyncEnumerable<IGrouping<bool?, TSource>>, ...)
  • PartitionAsync<TKey, TElement, TResult>(IAsyncEnumerable<IGrouping<TKey, TElement>>, ...)
  • PartitionAwaitAsync<TSource, TResult>(IAsyncEnumerable<IGrouping<bool, TSource>>, ...)
  • PartitionAwaitAsync<TSource, TResult>(IAsyncEnumerable<IGrouping<bool?, TSource>>, ...)
  • PartitionAwaitAsync<TKey, TElement, TResult>(IAsyncEnumerable<IGrouping<TKey, TElement>>, ...)

Migration: Update any code that passes IAsyncGrouping to these methods to use IGrouping instead. Since GroupBy in System.Linq.AsyncEnumerable now returns IGrouping, this should be a straightforward change.

Full Changelog: https://github.com/i3arnon/MoreAsyncLINQ/commits/v1.0.0