- Notifications
You must be signed in to change notification settings - Fork101
Variables and Functions
| Constant | Value | Type |
|---|---|---|
| null | C# null value | N/A |
| true | C# true value | System.Boolean |
| false | C# false value | System.Boolean |
| Pi | 3.14159265358979 | System.Double |
| E | 2.71828182845905 | System.Double |
You can define your own variables
Examples :
Live examples here
ExpressionEvaluatorevaluator=newExpressionEvaluator();evaluator.Variables=newDictionary<string,object>(){{"x",2.5},{"y",-3.6},{"myVar","Hello World"},{"myArray",newobject[]{3.5,"Test",false}},};
x+y-1.1myVar + " !!!"Hello World !!!myArray.Length3myArray[0]3.5myArray[1].Length4myArray[2] || trueTrueA very useful functionality is that you can store callable delegates in variables :
ExpressionEvaluatorevaluator=newExpressionEvaluator();evaluator.Variables=newDictionary<string,object>(){{"Add",newFunc<int,int,int>((x,y)=>x+y)},{"SayHelloTo",newAction<string>(name=>Console.WriteLine($"Hello{name} !!!"))},};
Add(5, 9)14SayHelloTo("John")Hello John !!!{null}From version 1.4.9.0 you can setSubExpression variables that are evaluate as an expression when they are met.
ExpressionEvaluatorevaluator=newExpressionEvaluator();evaluator.Variables["a"]=1;evaluator.Variables["b"]=2;evaluator.Variables["c"]=newSubExpression("a+b");evaluator.Variables["d"]=newSubExpression("c+3");evaluator.Variables["e"]="c+3";
a1b2c3d6d-a5ec+3From version 1.4.6.0, in addition of theVariables dictionary, you can also provide aContext object from which all public properties, fields and methods are directly available.
publicclassPerson{publicstringname;publicstringLastName{get;set;}publicDateTimeBirthDate{get;set;}publicintGetTheAgeIfTodayIs(DateTimedate){varage=date.Year-BirthDate.Year;if(BirthDate.Date>date.AddYears(-age))age--;returnage;}}// ...evaluator.Context=newPerson(){name="John",LastName="Smith",BirthDate=newDateTime(1985,09,11)};
name + " " + LastNameJohn SmithGetTheAgeIfTodayIs(new DateTime(2016, 5, 14))30The following functions are internally defined. (Most of these areSystem.Math Methods directly accessible)
| Name | Description | Example | Result |
|---|---|---|---|
| Abs(double number) | Return a double that is the absolute value of number | Abs(-3.2d) | 3.2d |
| Acos(double d) | Return a double value that is the angle in radian whose d is the cosine d must be betwteen -1 and 1 | Acos(-0.5d) | 2.0943951023032d |
| Array(object obj1, object obj2 ,...) | Return a array (System.Object[]) of all given arguments | Array(1, "Hello", true) | new object[]{1, "Hello", true} |
| ArrayOfType(Type typeOfTheArray, object obj1, object oj2, ...) | Return a array of the specified type | ArrayOfType(typeof(char), ',',';') | new char[]{',', ';'} |
| Asin(double d) | Return a double value that is the angle in radian whose d is the sine d must be betwteen -1 and 1 | Asin(-0.2d) | 0.304692654015398d |
| Atan(double d) | Return a double value that is the angle in radian whose d is the tangent | Atan(2.1) | 1.1263771168938d |
| Atan2(double x, double y) | Return a double value that is the angle in radian whose the tangente is the quotient of x and y | Atan2(2.1d, 3.4d) | 0.553294325322293d |
| Avg(double nb1, double nb2 ,...) | Return a double value that is the average value of all given arguments | Avg(1, 2.5, -4, 6.2) | 1.425d |
| Ceiling(double a) | Return a double value that is the smallest integer greater than or equal to the specified number. | Ceiling(4.23d) | 5d |
| Cos(double angle) | Return a double value that is the cosine of the specified angle in radian | Cos(2 * Pi) | 1d |
| Cosh(double angle) | Return a double value that is the hyperbolic cosine of the specified angle in radian | Cosh(2d) | 3.76219569108363d |
| Evaluate(string expression) | Return the result of the evaluation of the given expression. You can disable it withOptionEvaluateFunctionActive | Evaluate("1+2") | 3d |
| Exp(double d) | Return a double value that is e raised to the specified d power | Exp(3d) | 20.0855369231877d |
| Floor(double d) | Return a double value that is the largest integer less than or equal to the specified d argument | Floor(4.23d) | 4d |
| IEEERemainder(double x, double y) | Return a double value that is the remainder resulting from the division of x by y | IEEERemainder(9, 8) | 1d |
| in(object valueToFind, object obj1, object obj2...) | Return a boolean value that indicate if the first argument is found in the other arguments | in(8, 4, 2, 8) | true |
| List(object obj1, object obj2 ,...) | Return a List (System.Collections.Generic.List) of all given arguments | List(1, "Hello", true) | new List<object>(){1, "Hello", true} |
| ListOfType(Type typeOfTheList, object obj1, object oj2, ...) | Return a List of the specified type | ListOfType(typeof(string), "Text1","Text2") | new List<string>{"Text1", "Text2"} |
| Log(double a, double base) | Return a double value that is the logarithm of a in the specified base | Log(64d, 2d) | 6d |
| Log10(double a) | Return a double value that is the base 10 logarithm of a specified a | Log10(1000d) | 3d |
| Max(double nb1, double nb2 ,...) | Return a double value that is the maximum value of all given arguments | Max(1d, 2.5d, -4d) | 2.5d |
| Min(double nb1, double nb2 ,...) | Return a double value that is the minimum value of all given arguments | Min(1d, 2.5d, -4d) | -4d |
| new(TypeOrClass, constructorArg1, constructorArg2 ...) | Create an instance of the specified class as first argument and return it. A optional list of additional arguments can be passed as constructor arguments | new(Random).next(0,10) | 5d // or a random value between 1 and 9 |
| Pow(double x, double y) | Return a double value that is x elevate to the power y | Pow(2,4) | 16d |
| Round(double d, (optional) int digits, (optional)MidpointRounding mode) | Rounds d to the nearest integer or specified number of decimal places. | Round(2.432,1) | 2.4d |
| ScriptEvaluate(string script) | Return the result of the evaluation of the given script. You can disable it withOptionScriptEvaluateFunctionActive | ScriptEvaluate("value = 1+2;\r\nif(value > 2)\r\nreturn \"OK\";\r\nelse\r\nreturn \"NOK\";") | "OK" |
| Sign(double d) | Return 1,-1 or 0 indicating the sign of d | Sign(-12) | -1d |
| Sin(double angle) | Return a double value that is the sine of the specified angle in radian | Sin(Pi/2) | 1d |
| Sinh(double angle) | Return a double value that is the hyperbolic sine of the specified angle in radian | Sinh(2d) | 3.62686040784702d |
| Sqrt(double d) | Return a double value that is the square root of the specified d value | Sqrt(4d) | 2d |
| Tan(double angle) | Return a double value that is the tangent of the specified angle in radian | Tan(Pi / 4) | 1d |
| Tanh(double angle) | Return a double value that is the hyperbolic tangent of the specified angle in radian | Tanh(2d) | 0.964027580075817d |
| Truncate(double d) | Return a double value that is the integer part of the specified d value | Truncate(2.45d) | 2d |
Remark : The old if function (NCalc style) has been removed. This to avoid conflicts with the new if, else if, else keywords in script mode. To do something similar on a expression level use the conditional operator( ? : ) instead.
In addition to custom variables, you can add variables and/or functions "on the fly" during evaluation.
To do so, 4 C# events are provided. They are fired at evaluation time.
2 events are fired before all evaluations of variables, fields, properties and functions and methods.These two events can be canceled so no further evaluations are done. They are always fired
2 events are fired after all "standard" evaluation of variables, fields, properties and functions and methods.These two events are only fired if no others evaluations succeed.It avoid conflicts but it has also some performance drawback
Before version 1.4.0.0 it had only 2 events (EvaluateVariable and EvaluateFunction) evaluated before but not cancelable
Remark : Can be use to define or redefine on object instances methods or properties
ExpressionEvaluatorevaluator=newExpressionEvaluator();// always evaluated before other var and func evaluationsevaluator.PreEvaluateVariable+=Evaluator_PreEvaluateVariable;evaluator.PreEvaluateFunction+=Evaluator_PreEvaluateFunction;// evaluated if no existing var or func existsevaluator.EvaluateVariable+=Evaluator_EvaluateVariable;evaluator.EvaluateFunction+=Evaluator_EvaluateFunction;//...privatestaticvoidEvaluator_PreEvaluateVariable(objectsender,VariablePreEvaluationEventArge){if(e.Name.Equals("myvar1")){e.Value=5;}elseif(e.Name.StartsWith("P")){e.CancelEvaluation=true;}}privatestaticvoidEvaluator_PreEvaluateFunction(objectsender,FunctionPreEvaluationEventArge){if(e.Name.Equals("Test")&&e.Args.Count==1){e.Value=$"It is a test for{e.EvaluateArg(0)}";}elseif(e.Name.StartsWith("A")){e.CancelEvaluation=true;}}privatestaticvoidEvaluator_EvaluateVariable(objectsender,VariableEvaluationEventArge){if(e.Name.ToLower().Equals("myvar2")){e.Value=8;}elseif(e.Name.Equals("MultipliedBy2")&&e.ThisisintintValue){e.Value=intValue*2;}elseif(e.Name.Equals("GenericAssembly")&&e.HasGenericTypes){// e.EvaluateGenericTypes() return a Type[]e.Value=e.EvaluateGenericTypes()[0].Assembly.GetName().Name;}}privatestaticvoidEvaluator_EvaluateFunction(objectsender,FunctionEvaluationEventArge){if(e.Name.ToLower().Equals("sayhello")&&e.Args.Count==1){e.Value=$"Hello{e.EvaluateArg(0)}";}elseif(e.Name.Equals("Add")&&e.ThisisintintValue){e.Value=intValue+(int)e.EvaluateArg(0);}elseif(e.Name.Equals("GenericNamespace")&&e.HasGenericTypes){// e.EvaluateGenericTypes() return a Type[]e.Value=e.EvaluateGenericTypes()[0].Namespace;}}
myvar1 + 27Pithrow an exception (Pi not found)Test(5)It is a test for 5Abs(-3)throw an exception (Abs not found)myVar2 + 210SayHello("Bob")Hello Bob3.MultipliedBy263.Add(2)5GenericNamespace<List<string>>()System.Collections.GenericGenericAssembly<string>mscorlibTo use extension methods ExpressionEvaluator need to know which classes implements extension methods.It can be done like this :
publicstaticclassStringExtendedMethods{publicstaticstringAddExtended(thisstringstr){returnstr+" extended";}}// ...ExpressionEvaluatorevaluator=newExpressionEvaluator(newDictionary<string,object>(){{"x","Test"}});evaluator.StaticTypesForExtensionsMethods.Add(typeof(StringExtendedMethods));
x.AddExtended()Test extendedRemark :
ExpressionEvaluator do not find extension methods by itself because depending on the size of your assembly it can be very slow.But if you want, you can use the following code snippet one time somewhere in an "init" place in your code
usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Reflection;usingSystem.Runtime.CompilerServices;// ...foreach(AssemblyassemblyinAppDomain.CurrentDomain.GetAssemblies()){foreach(Typetypeinassembly.GetTypes()){if(type.IsSealed&&!type.IsGenericType&&!type.IsNested&&type.GetMethods(BindingFlags.Static|BindingFlags.Public|BindingFlags.NonPublic).ToList().Any(method=>method.IsDefined(typeof(ExtensionAttribute),false))){evaluator.StaticTypesForExtensionsMethods.Add(type);}}}
Remark :
By default theStaticTypesForExtensionsMethods List containstypeof(Enumerable) to allow a bunch of Linq stuff
When using single expression evaluation.There are cases where we need to use void methods in a fluid syntax manner.
You only need to prefix the method name with "Fluid" or "Fluent"
// Example Add on ListList("hello","bye").FluidAdd("test").Count3List("hello","bye").Select(x=>x.ToUpper()).ToList().FluentAdd("test")[0]HELLOList("hello","bye").Select(x=>x.ToUpper()).ToList().FluentAdd("test")[1]BYEList("hello","bye").Select(x=>x.ToUpper()).ToList().FluentAdd("test")[2]testList("hello","bye").Select(x=>x.ToUpper()).ToList().FluentAdd("test").FluidForEach(t=>Console.WriteLine(t)).CountHELLOBYEtest3
If needed this fonctionality can be disabled with :
evaluator.OptionFluidPrefixingActive = false;In scripts you can declare and use variables.
The way to declare a variable from a script has evolved according of the version of ExpressionEvaluator you use.
An assignation of a variable that do not exists create it automatically. (Can contains any type)
Before version 1.4.0.0 of ExpressionEvaluator it was the only way to declare a variable.
From version 1.4.0.0 you can optionally use the keyword "var". (Can contains any type)
From version 1.4.3.0 you can declare strongly typed variable. (It limit the type that can contain a variable)or optionally use the keyword "dynamic".
// Only supported from version 1.4.3.0intx=2;stringtext="hello";List<string>myList=newList<string>();for(inti=0;i<10;i++)...// If you have an older version. Write this instead :// Still available (for old script compatibility)x=2;text="hello";myList=newList<string>();for(i=0;i<10;i++)...// From version 1.4.0.0 you can also write// Still available (for old script compatibility)var x=2;vartext="hello";varmyList=newList<string>();for(vari=0;i<10;i++)
Remark
All variables are injected in theevaluator.Variables dictionnary.
For strongly typed variable you can only define one time a variable with a specific name.
Warning if you use the same evaluator instance multiple times to callevaluator.ScriptEvaluate(script);with a script that declare strongly typed variables you will have an exception the second time.
Here is a small easy snippet of code to call between your calls ofevaluator.ScriptEvaluate(script); to manage this specific case :
// This code remove all strongly typed variables of the Variable dictionnary.evaluator.Variables.ToList().FindAll(kvp=>kvp.ValueisStronglyTypedVariable).ForEach(kvp=>evaluator.Variables.Remove(kvp.Key));
As lambda can be stored in variable and can be multiline in scripts you can use them to simulate function declaration.
--------------------------------------------Add = (x, y) => x+y;Add(3, 2);---------------- Result --------------------5--------------------------------------------SayHelloTo = (name) =>{ hello = "Hye"; return $"{hello} {name}";};SayHelloTo("Joe");---------------- Result --------------------Hye JoeRemark
You can also assign a lambda to aExpandoObject and so call it as it was a method of thisExpandoObject.
- Getting Started
- Variables and Functions
- Operators and Keywords
- C# Types Management
- ExpandoObject
- Code Comments Management
- Advanced Customization and Hacking
- Caching
- Options
- CultureInfoForNumberParsing
- OptionCaseSensitiveEvaluationActive
- OptionVariablesPersistenceCustomComparer
- OptionFluidPrefixingActive
- OptionForceIntegerNumbersEvaluationsAsDoubleByDefault
- OptionNumberParsingDecimalSeparator
- OptionNumberParsingThousandSeparator
- OptionFunctionArgumentsSeparator
- OptionInitializersSeparator
- OptionInlineNamespacesEvaluationRule
- OptionNewFunctionEvaluationActive
- OptionNewKeywordEvaluationActive
- OptionStaticMethodsCallActive
- OptionStaticProperiesGetActive
- OptionInstanceMethodsCallActive
- OptionInstanceProperiesGetActive
- OptionIndexingActive
- OptionStringEvaluationActive
- OptionCharEvaluationActive
- OptionEvaluateFunctionActive
- OptionVariableAssignationActive
- OptionPropertyOrFieldSetActive
- OptionIndexingAssignationActive
- OptionScriptEvaluateFunctionActive
- OptionOnNoReturnKeywordFoundInScriptAction
- OptionScriptNeedSemicolonAtTheEndOfLastExpression
- OptionAllowNonPublicMembersAccess
- Todo List