.NET 10 adds LeftJoin, RightJoin, and Shuffle to LINQ. On .NET Framework 4.8 you still write a left join as GroupJoin + SelectMany + DefaultIfEmpty, and shuffle with OrderBy(_ => Guid.NewGuid()). Both are easy to get subtly wrong.
This is a short summary. The full article, with the complete polyfill and a net48 vs net10.0 output comparison, is here:
Expressing SQL Outer Joins in LINQ — Implementing LeftJoin, RightJoin and Shuffle
The core of the polyfill
LeftJoin wraps the classic idiom behind the .NET 10 signature, with TInner? marking the side that can be missing:
return outer
.GroupJoin(inner, outerKeySelector, innerKeySelector, (o, inners) => new { o, inners }, comparer)
.SelectMany(g => g.inners.DefaultIfEmpty(), (g, i) => resultSelector(g.o, i));
RightJoin pivots the same GroupJoin onto the inner sequence. The whole file sits behind #if !NET10_0_OR_GREATER, so it switches off after migration.
Three things worth knowing
-
Shuffleis a one-pass Fisher–Yates, not a GUID sort. On .NET Framework, eight threads that each creatednew Random()at the same moment produced the same order in the measurement. The fix seeds each thread from one locked instance. -
It re-shuffles on every enumeration. Call
ToArrayonce if you need a fixed order. -
Do not use it on
IQueryable<T>. TheEnumerablemethod still binds, so an Entity Framework join silently runs in memory. Keep theGroupJoinform for database queries.
A Japanese version is also available.
Related Articles
- Designing LINQ Polyfills That Preserve Lazy Evaluation — Implementing Append, Prepend, TakeLast and SkipLast
- Replacing GroupBy and Full-Sort Workarounds — Implementing Chunk, MaxBy, MinBy and DistinctBy
- Order and OrderDescending by Pure Delegation — A Minimal Polyfill with IOrderedEnumerable Compatibility
- Selector-Free ToDictionary — Designing for Overload Resolution and the notnull Constraint
- Key-Based Aggregation Without GroupBy — Dictionary-Backed CountBy, AggregateBy and Index
- Why a WPF RadioButton Bound to an Enum Shows No Initial Selection — The Role of GroupName
- C# Operators and Initialization Syntax by Version
- C# 14 Extension Members on Static Classes: Static Members Only
Top comments (0)