Skip to content

Conversation

idg10
Copy link
Collaborator

@idg10 idg10 commented Sep 30, 2025

.NET 10 includes System.Linq.AsyncEnumerable (and this is available for older .NET runtimes as a NuGet package). This provides LINQ for IAsyncEnumerable<T>, which is the primary raison d'être of the System.Linq.Async package that is built as part of Ix.NET.

The current version of System.Linq.Async (v6) causes problems if you use it in a project where System.Linq.AsyncEnumerable is also in use (e.g., any .NET 10.0 project).

This modifies System.Linq.Async to enable it to coexist with System.Linq.AsyncEnumerable (by removing most of the functionality from the public API visible in its ref assemblies, while leaving everything present in the runtime assemblies for binary compatibility). The small amount of functionality in System.Linq.Async that has not been recreated in System.Linq.AsyncEnumerable moves into System.Interactive.Async. The goal is for projects to be able to remove System.Linq.Async, and for us to deprecate this package.

The various oddly-named overloads that take async callbacks (with suffixes such as Await and WithCancellation) remain but have been marked as [Obsolete] with messages recommending that the developer move over to their more conventionally named equivalents from System.Linq.AsyncEnumerable.

Resolves #2239

The main job at this stage was to ensure it can still compile. This starts the job of separating out the duplicated and different APIs, but most of that remains to be done.
Turns out the solution doesn't build the ref assemblies and they weren't building.

I also needed to modify the async code generator to correctly handle #if-ed out code. Turns out it was stripping the directives and then copying the disabled block of text in as leading trivia! This had the effect of copying #if-ed out methods into the generated code, making them reappear.

I've also worked through the first four files of operators.
This is more complex than anything else so far for a couple of reasons.

First this uses T4 templates to generate code which in turn contains the [GenerateAsyncOverload] attribute, so we have two levels of code generation.

Second, System.Linq.AsyncEnumerable has elected not to implement all of the functionality available in System.Linq.Async (e.g. overloads taking selector callbacks).
Fix erroneous doc comment on ZIP
@idg10 idg10 added [area] Ix System.Linq.Async deprecation Replacing `System.Linq.Async` with the .NET class library's `System.Linq.AsyncEnumerable` labels Sep 30, 2025
idg10 added 13 commits October 8, 2025 08:35
The ref System.Linq.Async had different frameworks from the runtime one!

System.Interactive.Async now has responsibility for supplying the transitive dependency on Microsoft.Bcl.AsyncInterfaces when required. (System.Linq.Async used to do this, but we've inverted the dependency between these tow packages, and also we want people to stop using System.Linq.Async. Now that System.Interactive.Async is the leaf of the dependency tree, it's the one that has to add this reference.)

Also, I've added comments explaining why some projects have net10.0 but not net8.0 targets. (Since I very nearly incorrectly reverted that in a review just now, I think it's safe to say the reason behind this isn't entirely self-evident.)
@idg10 idg10 marked this pull request as ready for review October 10, 2025 06:35
@idg10 idg10 self-assigned this Oct 10, 2025
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR modifies the System.Linq.Async library to prepare for coexistence with the new .NET 10 System.Linq.AsyncEnumerable package. The changes enable System.Linq.Async to work alongside the official Microsoft implementation while providing binary compatibility.

  • Updates project files to use .NET 10.0 runtime and removes .NET 6.0 dependencies
  • Conditionally compiles most LINQ operators using the INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES flag
  • Marks overlapping functionality as obsolete with migration guidance to System.Linq.AsyncEnumerable
  • Moves unique functionality that isn't in System.Linq.AsyncEnumerable to System.Interactive.Async

Reviewed Changes

Copilot reviewed 119 out of 120 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
azure-pipelines.ix.yml Updates build pipeline to use .NET 10.x SDK and .NET 8.0 runtime
version.json Bumps version from 6.1.0 to 7.0.0 preview
refs/System.Linq.Async/*.csproj Updates target frameworks from net6.0 to net10.0/net8.0 and adds project references
Tests.System.Interactive.ApiApprovals/*.csproj Updates test packages to newer versions and adds System.Linq.AsyncEnumerable reference with alias
System.Linq.Async/System/Linq/Operators/*.cs Conditionally compiles duplicate LINQ operators and marks async callback variants as obsolete
Comments suppressed due to low confidence (1)

Ix.NET/Source/System.Linq.Async/System/Linq/Operators/Sum.Generated.tt:1

  • Corrected spelling of 'usef' to 'used'.
<#@ template debug="false" hostspecific="false" language="C#" #>

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@idg10 idg10 merged commit 1ce85f4 into main Oct 10, 2025
5 checks passed
@idg10 idg10 deleted the feature/2239-sys-linq-async-replacement branch October 10, 2025 16:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[area] Ix System.Linq.Async deprecation Replacing `System.Linq.Async` with the .NET class library's `System.Linq.AsyncEnumerable`

Projects

None yet

Development

Successfully merging this pull request may close these issues.

System.Linq.Async to System.Linq.AsyncEnumerable migration

2 participants