An open API service indexing awesome lists of open source software.

https://github.com/nilproject/nil.exev


https://github.com/nilproject/nil.exev

Last synced: 10 months ago
JSON representation

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");
```