Creating Func delegates using TextToCalcExpression





5.00/5 (2 votes)
This article how you can use TextToCalcExpression to generate Linq Expressions in runtime
Introduction
TextToCalcExpression is a project that i am developing on my free time, it's main goal it's to provide me and others with a free and simple to use LINQ Expressions generator for mathematical functions.
Background
For quite some time I was on the lookout for expression compilers that have nice licenses and don't have external dependencies, namely to parser generator runtime libraries.
I have found some that met most of my criteria like Text To Delegate, which is very complete, but I wasn't too happy with the license and found the code difficult to change to my needs.
Having lost a lot of time searching I set my mind into hacking out an Linq Expression generator, that I could use as a library or embed into my projects.
Please note that TextToCalcExpression is pretty much into alpha territory, so there's still a lot of testing to do.
Using the code
You can get the project's code on GitHub following this link.
After compiling and adding to one of your project's, using the code is rather simple.
ExpressionBuilder builder = new ExpressionBuilder();
Expression<Func<int,int, int>> expression = builder.Create<Func<int,int, int>>("A + B");
Func<int,int, int> func = expression.Compile();
int result = func(2,3);
// which will result in getting a 5
The expression builder creates Lambda Expressions from text, for creating expressions you will need to choose which delegate you want to use, input types and output type. You can compile when you need it and use the delegate.
TextToCalcExpression supports arithmetical and logic operations, plus some useful functions (Sine, Cosine, Tangent, Square Root, etc). It will not, though, infer the output type from the resulting operation, so you must choose the correct generic parameters.
Here are some examples:
ExpressionBuilder builder = new ExpressionBuilder();
Expression<Func<int,int, int>> expression =
builder.Create<Func<int,int, int>>("(A + 1) ^ B + 2");
Func<int,int, int> func = expression.Compile();
int result = func(2,3);
// which will result in getting a 29
Expression<Func<bool,bool,bool>> expression2 =
builder.Create<Func<bool,bool,bool>>("A==A AND (A!=B OR B==B)");
Func<bool,bool,bool> func2 = expression2.Compile();
bool result2 = func2(true,false);
// which will result in getting a true value
You can add as many parameters as you need, but have in mind that the order of entry of the parameters will be the same as they appear in the function text.
If you need to use trigonometry or other available functions, here are some examples:
ExpressionBuilder builder = new ExpressionBuilder();
Expression<Func<double,double>> expression =
builder.Create<Func<double, double>>("SIN(A)^2+COS(PI)^2");
Func<double,double> func = expression.Compile();
double result = func(Math.PI);
// which will result in getting a 1
Expression<Func<double,double>> expression2 = builder.Create<Func<double, double>>("LN A");
Func<double,double> func2 = expression2.Compile();
double result2 = func2(Math.E);
// which will result in getting a 1 also
Notice that PI and E constant are also available, so you can use them as well.
Keep in mind that TextToCalcExpression is case sensitive.
You can also use TextToCalcExpression to evaluate expressions, here are some examples of what is possible.
ExpressionBuilder builder = new ExpressionBuilder();
Expression<Func<int>> expression = builder.Create<Func<int>>("(2^3+2-1)/3");
Func<int> func = expression.Compile();
int result = func();
// which will result in getting a 3
Expression<Func<bool>> expression2 = builder.Create<Func<bool>>("NOT(false) AND true");
Func<bool> func2 = expression2.Compile();
bool result2 = func2();
// which will result in getting a true value
Expression<Func<bool>> expression3 = builder.Create<Func<bool>>("2 > 3 AND 1 >= 2");
Func<bool> func3 = expression3.Compile();
bool result3 = func3();
// which will result in getting a false value
Points of Interest
The primary idea on this expression generator is zero external dependencies, besides LINQ Expressions.
History
1st version - 2012/03/12.
2nd version - 2012/03/16.