FunctionalDev.ExpressionHelpers 2.1.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package FunctionalDev.ExpressionHelpers --version 2.1.0                
NuGet\Install-Package FunctionalDev.ExpressionHelpers -Version 2.1.0                
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="FunctionalDev.ExpressionHelpers" Version="2.1.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add FunctionalDev.ExpressionHelpers --version 2.1.0                
#r "nuget: FunctionalDev.ExpressionHelpers, 2.1.0"                
#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.
// Install FunctionalDev.ExpressionHelpers as a Cake Addin
#addin nuget:?package=FunctionalDev.ExpressionHelpers&version=2.1.0

// Install FunctionalDev.ExpressionHelpers as a Cake Tool
#tool nuget:?package=FunctionalDev.ExpressionHelpers&version=2.1.0                

FunctionalDev.ExpressionHelpers

Expression Helpers is a library which has been created to enable lambda expression serialisation and deserialisation.

With the help of this library, it is possible to convert from and to string literal representations of expression trees.

For example, (Person person) => Person.FirstName == "Fred" can be converted to "FirstName = 'Fred'" and vice versa.

This typically benefits two key areas of programming, configuration and dynamic API queries. Configuration can be enhanced allowing Expression<Func<T, bool>>/Func<T, bool> types to be read from configuration.

Dynamic API queries can be implemented by enabling something along the lines of IEnumerable<T> GetModels<T>(Expression<Func<T, bool>> filter); in the client library and having the API dynamically execute the query, unlocking significant performance and extension benefits. This could be taken further and executed in a Linq to SQL layer if an ORM such as Entity Framework is in use.

String Literal Breakdown

A string literal, in the context of this library, is a string which represents a serialised lambda expression. This can be broken down into segments which represent boolean conditions, chained together with chaining operators.

A string literal is built up with the following for constant/member evaluation. Members and constants can exist either side of the equation.

Constant values must be wrapped in single quotes, this denotes the internal expression as a constant value. "{Member/Constant} {Evaluation Symbol} {Member/Constant}" Methods can also be used. "{Member}.{Method Name}({Arguments as comma separated literals})" Note that nullable types and null avoidance are handled in deseralisation.

Evaluation Symbols

The following comparisons are possible.

Symbol Description
= Equals
!= Not Equals
> Greater Than
>= Greater Than or Equal
< Less Than
<= Less Than or Equal

Chaining Operators

Symbol Description
And The left part of the expression must resolve to true before the right part of the expression is evaluated. Both sides must resolve to true before the full expression returns true. Comparable to AndAlso.
Or If either the left or the right side of the expression resolves to true then the full expression returns true. The right side of the Or operator is only evaluated if the left resolves to false. Comparable to OrElse.

Examples

For the following class, some examples are listed below.

public class Person
{
	public string FirstName { set; get; }
	public int Age { set; get; }
	public IEnumerable<Person> Friends { set; get; }
}
var basicMemberLiteral = "FirstName = 'Fred'";
var alternativeMemberLiteral = "'Fred' = FirstName";
var numericalLiteral = "Age = '51'";
var methodLiteral = "FirstName.Contains('F')";
var nestedLambdaMethodLiteral = "Friends.Any(Age = '50')";
var chainedAndLiteral = "Friends.Any(Age = '50') And FirstName = 'Fred'";
var chainedOrLiteral = "Friends.Any(Age = '50') Or FirstName = 'Fred'";
var chainedComplexLiteral = "(Friends.Any(Age = '50') Or FirstName = 'Fred') And Age = '60'";
var nullLiteral = "FirstName = null";

Examples Calling Parser

// As expression.
Expression<Func<Person, bool>> parsed = ExpressionParser.Parse<Person>("FirstName = 'Fred');
// As Func.
Func<Person, bool> parsed = ExpressionParser.Parse<Person>("FirstName = 'Fred').Compile();

// literal will contain the value "Firstname = 'Fred'".
var literal = ExpressionParser.Parse((Person x) => x.FirstName == "Fred");

Also note that ExpressionParser contains non generic method alternatives for when the type is not known at compile time.

Remarks

Null comparisons are supported with the following syntax "FirstName = null".

Tokens

It is possible to tokenise a runtime expression. When calling to convert expression to string ExpressionParser.Parse use the ExpressionToken.Generate method to create a token expression which is then serialized as $Identifier$.

When calling ExpressionParser.Parse to convert from string to expression, use TokenDictionaryBuilder to provide an expression to resolve the token to.

Please see the following code for an example.

var serializedExpression = ExpressionParser.Parse<Person>(person => person.BirthDate > ExpressionToken.Generate<DateTime>("BirthDateComp"));
// serializedExpression now contains "BirthDate > $BirthDateComp$"
var deserializedExpression = ExpressionParser.Parse<Person>(serializedExpression, new TokenDictionaryBuilder{{"BirthDateComp", () => new DateTime(1990,10,16).AddDays(5)}}.Built);
// deserializedExpression now represents the following expression:
// person => person.BirthDate > new DateTime(1990,10,16).AddDays(5)

Limitations/Future Development

TBC.

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 was computed.  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. 
.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 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
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.
  • .NETStandard 2.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
2.1.3 139 9/17/2024
2.1.2 139 5/8/2024
2.1.1 112 5/7/2024
2.1.0 125 5/1/2024
2.0.1 145 4/4/2024
2.0.0 154 2/26/2024
1.1.1 137 2/7/2024
1.1.0 109 2/3/2024
1.0.4 515 1/27/2022
1.0.3 441 1/27/2022
1.0.2 433 1/26/2022
1.0.1 441 1/25/2022
1.0.0 449 1/25/2022