FunctionalDev.ExpressionHelpers
2.1.0
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
<PackageReference Include="FunctionalDev.ExpressionHelpers" Version="2.1.0" />
paket add FunctionalDev.ExpressionHelpers --version 2.1.0
#r "nuget: FunctionalDev.ExpressionHelpers, 2.1.0"
// 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 | 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.