FunctionalDev.ExpressionHelpers
2.1.3
dotnet add package FunctionalDev.ExpressionHelpers --version 2.1.3
NuGet\Install-Package FunctionalDev.ExpressionHelpers -Version 2.1.3
<PackageReference Include="FunctionalDev.ExpressionHelpers" Version="2.1.3" />
paket add FunctionalDev.ExpressionHelpers --version 2.1.3
#r "nuget: FunctionalDev.ExpressionHelpers, 2.1.3"
// Install FunctionalDev.ExpressionHelpers as a Cake Addin #addin nuget:?package=FunctionalDev.ExpressionHelpers&version=2.1.3 // Install FunctionalDev.ExpressionHelpers as a Cake Tool #tool nuget:?package=FunctionalDev.ExpressionHelpers&version=2.1.3
FunctionalDev.ExpressionHelpers
Overview
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.
Contents
- Basic Literals
- Overview - An overview of the string representation of an expression tree.
- Equality Comparison Operators - Comparison symbols supported by the parsers.
- Chaining Operators - Chaining operators supported by the parsers.
- Tokens - Token substitutions in expressions.
- Examples
- Version Control
Basic Literals
Basic Literals - Overview
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.
Basic Literals - Equality Comparison Operators
The following comparisons are possible.
Symbol | Description |
---|---|
= | Equals |
!= | Not Equals |
> | Greater Than |
>= | Greater Than or Equal |
< | Less Than |
<= | Less Than or Equal |
Basic Literals - 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. |
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. Example - Tokens
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; }
}
Examples - Calling Parser
Examples - Calling Parser - String Literal to Expression
Convert a string literal to an expression.
Expression<Func<Person, bool>> parsed = ExpressionParser.Parse<Person>("FirstName = 'Fred'");
Examples - Calling Parser - String Literal to Func
Compile the expression to a func (a delegate which can be executed at runtime).
Func<Person, bool> parsed = ExpressionParser.Parse<Person>("FirstName = 'Fred'").Compile();
Examples - Calling Parser - Expression to String Literal
Convert an expression to a string literal.
// 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.
Examples - Basic Equality
Note that constant values are always surrounded by single quotes, integer and boolean values included.
Examples - Basic Equality - String
The following two examples compare a property to a constant value.
var basicMemberLiteral = "FirstName = 'Fred'";
var alternativeMemberLiteral = "'Fred' = FirstName";
Examples - Basic Equality - Integer
The following two examples compare a property to a constant value.
var numericalLiteral = "Age = '51'";
Examples - Method Calls
All parts of an expression literal are evaluated the same, when an argument is found for a method call it's treated in the same way, constants, method calls and literals.
Most methods could be included but the service running the parser from literal to expression must be able to understand the method calls.
Examples - Method Calls - Constant Arguments
In the example below Contains is called on the string with an argument of "F"
.
var methodLiteral = "FirstName.Contains('F')";
Examples - Method Calls - Lambda Arguments
In the example below a lambda is being used in the Any method call.
var nestedLambdaMethodLiteral = "Friends.Any(Age = '50')";
Examples - Chaining
Examples of chaining expression trees.
Examples - Chaining - Mixing Method And Member Comparisons
Below are some examples of mixing functions (which need to resolve to a boolean) and chaining the response with other expressions.
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'";
Examples - Null
Null can be used in an equality expression, the null
text represents the Null monad.
var nullLiteral = "FirstName = null";
Examples - Tokens
Use tokens in string literals to represent a runtime substitution for a known expression.
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)
Version Control
2.1.3 | 17/09/2024
- Fixed endless looping on invalid expression.
2.1.1 | 07/05/2024
- Minor readme changes: fixed content link.
2.1.1 | 07/05/2024
- Introduced ChangeLog
Product | Versions 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. |
-
.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.