ZLinq.Json 1.4.4

There is a newer version of this package available.
See the version list below for details.
dotnet add package ZLinq.Json --version 1.4.4
                    
NuGet\Install-Package ZLinq.Json -Version 1.4.4
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ZLinq.Json" Version="1.4.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ZLinq.Json" Version="1.4.4" />
                    
Directory.Packages.props
<PackageReference Include="ZLinq.Json" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ZLinq.Json --version 1.4.4
                    
#r "nuget: ZLinq.Json, 1.4.4"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ZLinq.Json@1.4.4
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ZLinq.Json&version=1.4.4
                    
Install as a Cake Addin
#tool nuget:?package=ZLinq.Json&version=1.4.4
                    
Install as a Cake Tool

ZLinq

CI Benchmark NuGet DeepWiki

Zero allocation LINQ with LINQ to Span, LINQ to SIMD, and LINQ to Tree (FileSystem, JSON, GameObject, etc.) for all .NET platforms(netstandard2.0, 2.1, net8, net9) and Unity, Godot.

alternate text is missing from this package README image

Unlike regular LINQ, ZLinq doesn't increase allocations when adding more method chains, and it also has higher basic performance. You can check various benchmark patterns at GitHub Actions/Benchmark. ZLinq shows high performance in almost all patterns, with some benchmarks showing overwhelming differences.

As a bonus, LINQ operators and optimizations equivalent to .NET 10 can be used in .NET Framework 4.8 (netstandard2.0) and Unity (netstandard2.1).

dotnet add package ZLinq
using ZLinq;

var seq = source
    .AsValueEnumerable() // only add this line
    .Where(x => x % 2 == 0)
    .Select(x => x * 3);

foreach (var item in seq) { }
  • 99% compatibility with .NET 10's LINQ (including new Shuffle, RightJoin, LeftJoin operators)
  • Zero allocation for method chains through struct-based Enumerable via ValueEnumerable
  • LINQ to Span to full support LINQ operations on Span<T> using .NET 9/C# 13's allows ref struct
  • LINQ to Tree to extend tree-structured objects (built-in support for FileSystem, JSON, GameObject)
  • LINQ to SIMD to automatic application of SIMD where possible and customizable arbitrary operations
  • Optional Drop-in replacement Source Generator to automatically accelerate all LINQ methods

In ZLinq, we have proven high compatibility and performance by running dotnet/runtime's System.Linq.Tests as a drop-in replacement, passing 9000 tests.

alternate text is missing from this package README image

Previously, value type-based LINQ implementations were often experimental, but ZLinq fully implements all methods to completely replace standard LINQ in production use, delivering high performance suitable even for demanding applications like games. The performance aspects are based on my experience with previous LINQ implementations (linq.js, SimdLinq, UniRx, R3), zero-allocation implementations (ZString, ZLogger), and high-performance serializers (MessagePack-CSharp, MemoryPack).

ZLinq achieves zero-allocation LINQ implementation using the following structs and interfaces.

public readonly ref struct ValueEnumerable<TEnumerator, T>(TEnumerator enumerator)
    where TEnumerator : struct, IValueEnumerator<T>, allows ref struct
{
    public readonly TEnumerator Enumerator = enumerator;
}

public interface IValueEnumerator<T> : IDisposable
{
    bool TryGetNext(out T current); // as MoveNext + Current

    // Optimization helper
    bool TryGetNonEnumeratedCount(out int count);
    bool TryGetSpan(out ReadOnlySpan<T> span);
    bool TryCopyTo(scoped Span<T> destination, Index offset);
}

Besides changing to a struct-based approach, we've integrated MoveNext and Current to reduce the number of iterator calls. Also, some operators don't need to hold Current, which allows minimizing the struct size. Additionally, being struct-based, we efficiently separate internal state by copying the Enumerator instead of using GetEnumerator. With .NET 9/C# 13 or later, allows ref struct enables natural integration of Span<T> into LINQ.

public static ValueEnumerable<Where<TEnumerator, TSource>, TSource> Where<TEnumerator, TSource>(this ValueEnumerable<TEnumerator, TSource> source, Func<TSource, Boolean> predicate)
    where TEnumerator : struct, IValueEnumerator<TSource>, allows ref struct

Operators have this method signature. C# cannot infer types from generic constraints(dotnet/csharplang#6930). Therefore, the traditional Struct LINQ approach required implementing all operator combinations as instance methods, resulting in 100,000+ methods and massive assembly sizes. However, in ZLinq, we've successfully avoided all the boilerplate method implementations by devising an approach that properly conveys types to C# compiler.

Additionally, TryGetNonEnumeratedCount(out int count), TryGetSpan(out ReadOnlySpan<T> span), and TryCopyTo(Span<T> destination, Index offset) defined in the interface itself enable flexible optimizations. To minimize assembly size, we've designed the library to achieve maximum optimization with minimal method additions. For example, TryCopyTo works efficiently with methods like ToArray when combined with TryGetNonEnumeratedCount. However, it also allows copying to smaller-sized destinations. By combining this with Index, we can optimize First, Last, and ElementAt using just TryCopyTo by passing a single-element Span along with an Index.

Getting Started

You can install package from NuGet/ZLinq. For Unity usage, refer to the Unity section. For Godot usage, refer to the Godot section.

dotnet add package ZLinq

Use using ZLinq; and call AsValueEnumerable() on any iterable type to use ZLinq's zero-allocation LINQ.

using ZLinq;

var source = new int[] { 1, 2, 3, 4, 5 };

// Call AsValueEnumerable to apply ZLinq
var seq1 = source.AsValueEnumerable().Where(x => x % 2 == 0);

// Can also be applied to Span (only in .NET 9/C# 13 environments that support allows ref struct)
Span<int> span = stackalloc int[5] { 1, 2, 3, 4, 5 };
var seq2 = span.AsValueEnumerable().Select(x => x * x);

Even if it's netstandard 2.0 or below .NET 10, all operators up to .NET 10 are available.

You can method chain and foreach like regular LINQ, but there are some limitations. Please see Difference and Limitation for details. ZLinq has drop-in replacements that apply ZLinq without needing to call AsValueEnumerable(). For more information, see Drop-in replacement. Detailed information about LINQ to Tree for LINQ-ifying tree structures (FileSystems and JSON) and LINQ to SIMD for expanding SIMD application range can be found in their respective sections.

Additional Operators

In ZLinq, we prioritize compatibility, so we try to minimize adding custom operators. However, the following methods have been added to enable efficient processing with zero allocation:

AsValueEnumerable()

Converts existing collections to a type that can be chained with ZLinq. Any IEnumerable<T> can be converted, but for the following types, conversion is done with zero allocation without IEnumerable<T>.GetEnumerator() allocation. Standard supported types are T[], List<T>, ArraySegment<T>, Memory<T>, ReadOnlyMemory<T>, ReadOnlySequence<T>, Dictionary<TKey, TValue>, Queue<T>, Stack<T>, LinkedList<T>, HashSet<T>, ImmutableArray<T>, Span<T>,