Linq.Expression.Optimizer 1.0.41

There is a newer version of this package available.
See the version list below for details.
dotnet add package Linq.Expression.Optimizer --version 1.0.41
                    
NuGet\Install-Package Linq.Expression.Optimizer -Version 1.0.41
                    
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="Linq.Expression.Optimizer" Version="1.0.41" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Linq.Expression.Optimizer" Version="1.0.41" />
                    
Directory.Packages.props
<PackageReference Include="Linq.Expression.Optimizer" />
                    
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 Linq.Expression.Optimizer --version 1.0.41
                    
#r "nuget: Linq.Expression.Optimizer, 1.0.41"
                    
#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 Linq.Expression.Optimizer@1.0.41
                    
#: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=Linq.Expression.Optimizer&version=1.0.41
                    
Install as a Cake Addin
#tool nuget:?package=Linq.Expression.Optimizer&version=1.0.41
                    
Install as a Cake Tool

Issue Stats Issue Stats

Linq.Expression.Optimizer

Lightweight optimizer of System.Linq.Expression expressions. Just basic boolean algebra and reductions, constant and tuple/anonymous type eliminations. For side-effect-free Expressions. No compilation-subjective optimizations. This is meant to be used with expressions that are not compiled but transferred to other domains.

Supported frameworks: Net 3.5, Net 4.5-... (and Mono), .NET Standard 1.6 (so also .NET Core)

Supported optimizations

Example as a quote. There are various other cases also.

  • Replace constants comparisons: 3 < 4 -> true
  • Remove anonymous types: new AnonymousObject(Item1 = x, Item2 = "").Item1 --> x
  • Cut not used condition: if false then x else y -> y
  • Remove not: not(false) -> true
  • Binary tree balancing: a or (b or (c or (d or (e or (f or (g or h)))))) -> ((a or b) or (c or d)) or ((e or f) or (g or h))
  • Captured closure constant ("free variable") evaluation: y = 3 and (y + x) -> (3 + x)
  • Execute simple math: 5 * 3 -> 15
  • Boolean algebra reductions:
    • gather (x or y) and (x or z) -> x or (y and z)
    • identity false or y -> y
    • annihilate true or x -> true
    • absorb x and (x or y) -> x
    • idempotence y or y -> y
    • complement x and not(x) -> false
    • doubleNegation not(not(y)) -> y
    • deMorgan not(x) and not(y) -> not(x or y)

What a rewrite keeps

The optimized expression gives the value of the original for every input and throws only where the original throws. Optimizing a valid tree does not throw.

  • Evaluation order. A rewrite may evaluate fewer operands, but never one the original would have skipped, and the operands that stay keep their left-to-right order: a guard stays ahead of what it guards (o != null and o.Flag). An exception the original would throw may disappear with a subtree that is optimized away.
  • The same operand. Two operands are one only when they are the same parameter (by reference, not by name), constants holding the same reference (the same value for value types and strings), or the same member chain over those. Anything holding a method call, an Invoke, a New or an index is never the same as another.
  • Arithmetic. Constants are regrouped ((x + 2) + 3 -> x + 5) for integral types in unchecked nodes only. Identities are applied where they are exact: not x + 0.0 (it turns -0.0 into 0.0), not x * 0 or x % 1 on a Nullable. A decimal is the same by value: its constants are folded and its identities applied, and a result may carry another scale than the original's (6.0 for 6.00). A fold that overflows is left for the run time.
  • Operators. A node is folded or rewritten only when its operator is the built-in one: no Method; an op_* method of string, decimal, DateTime, DateTimeOffset, TimeSpan, Guid or BigInteger (also the static String.Concat and String.Equals); or an F# operator (Operators.op_*, LanguagePrimitives.*Dynamic) over those types, primitives, enums, and options, lists, tuples and Nullables of them. Objects are compared by reference, never by value.
  • Comparison ranges (x > 1 and x > 2 -> x > 2) are left alone over Nullable operands and NaN constants.
  • Tuples and anonymous types. A tuple is a System.Tuple, a System.ValueTuple or an AnonymousObject; a member of an anonymous type is found through NewExpression.Members.
  • Other nodes. A node type without a rule (Default, Index, Switch, Try, ...) stays as it is.
  • Deep trees. A tree nested deeper than the stack has room for is optimized down to that depth and left as it is below, instead of overflowing the stack.
  • Captured values. A captured closure constant is read when the expression is optimized: the optimized expression does not see a later change of the captured variable.

Background

This is a side-track from SQLProvider, excellent tool that is kind of OR-mapper with auto-generated objects, so it compiles any databases to .NET-language, and works fast on design time in Visual Studio or other editors.

But I needed better SQL-queries. So this optimises .NET LINQ-expressions. These expressions were not meant to be compiled, so Nessos LinqOptimizer was not the right tool. I thought that .NET would optimize these automatically, but no.

Read the Getting started tutorial to learn more.

Documentation: http://thorium.github.io/Linq.Expression.Optimizer

Tests

tests/Linq.Expression.Optimizer.Tests is the example-based suite over LINQ queries. tests/Linq.Expression.Optimizer.PropertyTests is an FsCheck suite over random expression trees (booleans, integers, doubles with NaN, decimals, nullable integers, strings and an object that may be null over fifteen parameters, two of them named alike and two unnamed, in the shapes every reduction rule is written for): the optimized tree compiles to the same function as the original on a grid of inputs, optimizing never throws, optimizing twice is optimizing once, the tree never grows, and every reduction rule fires on some generated tree. An exception the original would throw (x / 0, null.Length) may disappear when the subtree that threw it is optimized away - the library is for side-effect-free expressions - but a value never changes and no new exception appears.

Maintainer(s)

If you want more optimizations, please feel free to send PRs!

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 is compatible. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (4)

Showing the top 4 NuGet packages that depend on Linq.Expression.Optimizer:

Package Downloads
Dosaic.Plugins.Persistence.EfCore.Abstractions

A plugin-first dotnet framework for rapidly building anything hosted in the web.

Dosaic.Plugins.Persistence.EfCore.NpgSql

A plugin-first dotnet framework for rapidly building anything hosted in the web.

SpeedyCourse.Entities

Package Description

XSpecification.Linq

XSpecification is an implementation of Specification pattern for Linq and Elasticsearch

GitHub repositories (3)

Showing the top 3 popular GitHub repositories that depend on Linq.Expression.Optimizer:

Repository Stars
rnwood/smtp4dev
smtp4dev - the fake smtp email server for development and testing
scottksmith95/LINQKit
LINQKit is a free set of extensions for LINQ to SQL and Entity Framework power users.
zzzprojects/System.Linq.Dynamic.Core
The .NET Standard / .NET Core version from the System Linq Dynamic functionality.
Version Downloads Last Updated
1.0.42 398 11/11/2026
1.0.41 141 11/11/2026
1.0.39 22,356 6/11/2026
1.0.38 215 6/9/2026
1.0.37 496 6/8/2026
1.0.36 1,223 5/26/2026
1.0.35 6,731 4/8/2026
1.0.34 72,300 11/9/2025
1.0.33 3,140 9/8/2025
1.0.32 2,427 6/19/2025
1.0.31 802 6/4/2025
1.0.29 15,798 3/31/2025
1.0.28 1,771 3/26/2025
1.0.27 1,093 3/18/2025
1.0.24 12,620 11/7/2024
1.0.23 47,182 6/26/2024
1.0.22 671 6/26/2024
Loading failed

Visited expressions are cached per run: a shared or rewritten subtree is reduced once
A constant MinValue / -1 and an empty-string concatenation of a nullable string are left alone
A tree nested deeper than the stack is optimized down to that depth instead of overflowing it
Parameters match by reference, not by name and type
Boolean rewrites keep the evaluation order: no operand is read ahead of its guard
Anonymous type members map to constructor arguments through NewExpression.Members
Tuples are recognised by type (System.Tuple, System.ValueTuple, AnonymousObject), not by a name starting with Tuple
x - x and c ? y : y compare their operands structurally, not by ToString
Range rewrites skip NaN constants and nullable operands; string ranges are ordinal and keep the comparison's method
Constants are regrouped for integral types only; float and nullable identities are applied only where exact; a decimal result is the same by value and may carry another scale
Nodes with a user-defined Method are not folded, and objects are not compared by value
No exception on string + object concatenation, a constant query over a list on .NET Framework, Nullable<bool> constants, typed conditionals, blocks without variables, node types without a rule, or a constant member or fold that throws