Skip to content

Commit ff62b6e

Browse files
committed
Delegates as a variable
1 parent 59421bd commit ff62b6e

File tree

3 files changed

+46
-13
lines changed

3 files changed

+46
-13
lines changed

CodingSeb.ExpressionEvaluator.Tests/ExpressionEvaluatorTests.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,6 +1001,18 @@ public static IEnumerable<TestCaseData> TestCasesForWithCustomVariablesExpressio
10011001
yield return new TestCaseData("simpleInt-- - simpleInt", onInstanceVariables, true).SetCategory("Postfix operator, --").Returns(1);
10021002
#endregion
10031003

1004+
#region Delegates as a variable
1005+
1006+
Dictionary<string, object> delegatesInVariable = new Dictionary<string, object>()
1007+
{
1008+
{ "Add", new Func<int,int,int>((x, y) => x + y)},
1009+
{ "Test", new Action<int>(x => x.ShouldEqual(5))},
1010+
};
1011+
1012+
yield return new TestCaseData("Add(3, 4)", delegatesInVariable, true).SetCategory("Delegate as a variable").Returns(7);
1013+
yield return new TestCaseData("Test(5)", delegatesInVariable, true).SetCategory("Delegate as a variable").Returns(null);
1014+
1015+
#endregion
10041016
}
10051017
}
10061018

CodingSeb.ExpressionEvaluator/ExpressionEvaluator.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1307,10 +1307,14 @@ private bool EvaluateVarOrFunc(string expr, string restOfExpression, Stack<objec
13071307
{
13081308
stack.Push(funcResult);
13091309
}
1310-
else if(Variables.TryGetValue(varFuncName, out object o) && o is InternalDelegate lambdaExpression)
1310+
else if (Variables.TryGetValue(varFuncName, out object o) && o is InternalDelegate lambdaExpression)
13111311
{
13121312
stack.Push(lambdaExpression.Invoke(funcArgs.ConvertAll(e => Evaluate(e)).ToArray()));
13131313
}
1314+
else if (Variables.TryGetValue(varFuncName, out o) && o is Delegate delegateVar)
1315+
{
1316+
stack.Push(delegateVar.DynamicInvoke(funcArgs.ConvertAll(e => Evaluate(e)).ToArray()));
1317+
}
13141318
else
13151319
{
13161320
FunctionEvaluationEventArg functionEvaluationEventArg = new FunctionEvaluationEventArg(varFuncName, Evaluate, funcArgs);

README.md

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
A Simple Math and Pseudo C# Expression Evaluator in One C# File.
44

5-
And now can execute small C# like scripts
5+
And from version 1.2.0 can execute small C# like scripts
66

7-
It is largely based on and inspired by the following resources [this post on stackoverflow](http://stackoverflow.com/questions/333737/evaluating-string-342-yield-int-18/333749), [NCalc](https://ncalc.codeplex.com/) and [C# Operators](https://msdn.microsoft.com/en-us/library/6a71f45d.aspx)
7+
It is largely based on and inspired by the following resources [this post on stackoverflow](http://stackoverflow.com/questions/333737/evaluating-string-342-yield-int-18/333749), [NCalc](https://ncalc.codeplex.com/), [C# Operators](https://msdn.microsoft.com/en-us/library/6a71f45d.aspx) and [C# Statement Keywords](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/statement-keywords)
88

99
## Status
1010

@@ -32,7 +32,7 @@ It is largely based on and inspired by the following resources [this post on st
3232
* Manage now assignation operators like =, +=, -=, *= ... (On variables and sub properties)
3333
* Manage now postfix operators ++ and -- (On variables and sub properties)
3434

35-
## And with [ScriptEvaluate](#scripts)
35+
## And with [ScriptEvaluate](#scripts) method
3636
* Small C# like script evaluation (Multi expressions separated by ;)
3737
* Some conditional and loop blocks [keywords](#script-keywords) (if, while, for ...)
3838
* Multi-line (multi expression) Lambda expressions.
@@ -279,8 +279,6 @@ To see more scripts examples see scripts uses for tests in sub directories [Codi
279279

280280
## Standard constants (variables)
281281

282-
The evaluation of variables name is case insensitive so you can write it as you want.
283-
284282
|Constant|Value|Type|
285283
|---|---|---|
286284
|null|C# null value|N/A|
@@ -300,8 +298,8 @@ evaluator.Variables = new Dictionary<string, object>()
300298
{
301299
{ "x", 2,5 },
302300
{ "y", -3.6 },
303-
{ "myVar", "Hello World" }
304-
{ "myArray", new object[] { 3.5, "Test", false}
301+
{ "myVar", "Hello World" },
302+
{ "myArray", new object[] { 3.5, "Test", false },
305303
};
306304
```
307305
```
@@ -323,6 +321,23 @@ myArray[1].Length
323321
myArray[2] || true
324322
True
325323
```
324+
A very useful functionality is that you can store callable delegates in variables :
325+
```C#
326+
ExpressionEvaluator evaluator = new ExpressionEvaluator();
327+
evaluator.Variables = new Dictionary<string, object>()
328+
{
329+
{ "Add", new Func<int,int,int>((x, y) => x + y)},
330+
{ "SayHelloTo", new Action<string>(name => Console.WriteLine($"Hello {name} !!!"))},
331+
};
332+
```
333+
```
334+
Add(5, 9)
335+
14
336+
337+
SayHelloTo("John")
338+
Hello John !!!
339+
{null}
340+
```
326341

327342
## Standard functions
328343
The following functions are internally defined. (Most of these are [System.Math Methods](https://msdn.microsoft.com/en-us/library/system.math(v=vs.110).aspx) directly accessible)
@@ -365,8 +380,8 @@ The following functions are internally defined. (Most of these are [System.Math
365380
## On the fly variables and functions evaluation
366381
In addition to custom variables, you can add variables and/or functions with on the fly evaluation.
367382
2 C# events are provided that are fired when variables or functions are not fund as standard ones in evaluation time.
368-
Can be use to define or redefine on object instances methods or properties.
369383

384+
*Remark : Can be use to define or redefine on object instances methods or properties*
370385
```C#
371386
ExpressionEvaluator evaluator = new ExpressionEvaluator();
372387
evaluator.EvaluateVariable += ExpressionEvaluator_EvaluateVariable;
@@ -431,15 +446,14 @@ BYE
431446
List("hello", "bye").Select(x => x.ToUpper()).ToList().FluentAdd("test")[2]
432447
test
433448
```
434-
435449
If needed this fonctionality can be disabled with :
436450

437451
```
438452
evaluator.OptionFluidPrefixingActive = false;
439453
```
440454

441455
## Primary types
442-
ExpressionEvaluator manage the following list of C# primary types
456+
ExpressionEvaluator manage the following list of [C# primary types](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/built-in-types-table)
443457
444458
* object
445459
* string
@@ -586,6 +600,9 @@ Currently the following script keywords are supported
586600
|Jump|[continue](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/continue)|Supported in do, for and while blocks|
587601
|Jump|[goto](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/goto)|Not supported (But if you looked after it -> Booo !!! Bad code)|
588602
|Jump|[return](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/return)|Supported|
603+
|Jump|[yield](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/yield)|Not supported|
604+
605+
Exception handling keywords are not yet supported
589606

590607
*Remark : The way ScriptEvaluate works is to evaluate expressions one by one. There is no syntax check before the evaluation. So be aware that syntax or naming bugs only appears in execution and some code can already be evaluated at this time. Futhermore a syntaxic/naming bug in an if-else block for example can simply be ignored until the corresponding condition is met to evaluate the specific line of code.*
591608

@@ -599,7 +616,7 @@ To be sure that your commented script is evaluated correctly you can do :
599616
ExpressionEvaluator evaluator = new ExpressionEvaluator();
600617
evaluator.ScriptEvaluate(evaluator.RemoveComments(scriptWithComments));
601618
```
602-
It remove line comments // and blocks comments /* ... */
619+
It remove line comments // and blocks comments /* ... */ but keep them in strings
603620
604621
## Namespaces and types
605622
By default the following list of namespaces are available :
@@ -623,7 +640,7 @@ evaluator.Namespaces.Add(namespace);
623640
evaluator.Namespaces.Remove(namespaceToRemove);
624641
```
625642

626-
All types define in these namespaces are accessibles.
643+
All types defined in these namespaces are accessibles.
627644

628645
You can also add a specific type :
629646

0 commit comments

Comments
 (0)