https://github.com/nilproject/nil.exev
https://github.com/nilproject/nil.exev
Last synced: 10 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/nilproject/nil.exev
- Owner: nilproject
- License: mit
- Created: 2023-04-25T10:02:43.000Z (about 3 years ago)
- Default Branch: master
- Last Pushed: 2023-11-18T11:35:26.000Z (over 2 years ago)
- Last Synced: 2025-08-01T01:08:42.133Z (11 months ago)
- Language: C#
- Size: 34.2 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.MD
- License: LICENSE
Awesome Lists containing this project
README
NiL.Exev
==
Custom evaluator and serializer for System.Linq.Expression.
What's the point?
it's up to 100 times faster then compile-and-run.
```c#
Expression> expression = (a, b) => a + b;
var repeats = 100_000;
var sw = Stopwatch.StartNew();
for (var i = 0; i < repeats; i++)
{
var result = expression.Compile()("hello, ", "world");
Debug.Assert(result is "hello, world");
}
Console.WriteLine(sw.Elapsed); // 00:00:03.8659292
var evaluator = new ExpressionEvaluator();
sw.Restart();
for (var i = 0; i < repeats; i++)
{
var result = evaluator.Eval(
expression.Body,
new[]
{
new Parameter(expression.Parameters[0], "hello, "),
new Parameter(expression.Parameters[1], "world")
});
Debug.Assert(result is "hello, world");
}
Console.WriteLine(sw.Elapsed); // 00:00:00.0391234
```
And only 10 times slower when both are prepared (but you can do not use it in this case, of course)
```c#
Expression> expression = (a, b) => a + b;
var repeats = 10_000_000;
var compile = expression.Compile();
var sw = Stopwatch.StartNew();
for (var i = 0; i < repeats; i++)
{
var result = compile("hello, ", "world");
Debug.Assert(result is "hello, world");
}
sw.Stop();
Console.WriteLine(sw.Elapsed); // 00:00:00.1274875
var evaluator = new ExpressionEvaluator();
var args = new[]
{
new Parameter(expression.Parameters[0], ""),
new Parameter(expression.Parameters[1], "")
};
sw.Restart();
for (var i = 0; i < repeats; i++)
{
args[0].Value = "hello, ";
args[1].Value = "world";
var result = evaluator.Eval(expression.Body, args);
Debug.Assert(result is "hello, world");
}
sw.Stop();
Console.WriteLine(sw.Elapsed); // 00:00:01.1773341
```
And what? When it can be helpful?
When you are making you own super-duper-mega RPC protocol
```C#
// Сharacters
var myDb = new Dictionary { ["someKey"] = "someValue" }; // some class to access to data on a server
var serializer = new ExpressionSerializer();
var deserializer = new ExpressionDeserializer();
var evaluator = new ExpressionEvaluator();
var networkStream = new MemoryStream(); // just imagine that this is network stream
// Client
Expression, string>> expression = serverDictionary => serverDictionary["someKey"];
var serialized = serializer.Serialize(expression);
networkStream.Write(serialized); // transfer to a server
networkStream.Seek(0, SeekOrigin.Begin);
// Server
var receivedRequest = new byte[networkStream.Length];
networkStream.Read(receivedRequest, 0, receivedRequest.Length);
var deserialized = deserializer.Deserialize(receivedRequest);
var result = (evaluator.Eval(deserialized) as Func, string>)!(myDb);
var serializedResult = serializer.Serialize(Expression.Constant(result));
networkStream.SetLength(0); // transfer to a client
networkStream.Write(serializedResult);
networkStream.Seek(0, SeekOrigin.Begin);
// Client
var receivedResponse = new byte[networkStream.Length];
networkStream.Read(receivedResponse, 0, receivedResponse.Length);
var response = deserializer.Deserialize(receivedResponse) as ConstantExpression;
Debug.Assert(response!.Value is "someValue");
```