0

I am trying to make a pair of programs in C# .NET Core one of which generates "templates" or "rules" in a form of text (XML, JSON, etc.) and the other translates it to code to be run. This is still at feasibility stage, so I am open to every recommendation. My specific problem concerns the reconstruction of delegates:

Is it possible to read a string, e.g. "x => x[1] > 0" and then convert this into a delegate to be used in Linq? For example can:

string myRule = "x => x[1] >= 18";

somehow be used in:

// for the example's sake, assume the following table has a fixed structure of "id, age" 
List<List<double>> myList = new List<List<double>>()
{
    new List<double>(){ 1, 25 },
    new List<double>(){ 2, 14 },
    new List<double>(){ 3, 30 }
};

int adults = myList.Count(StringToDelegate(myRule));
Console.WriteLine("Total adults " + adults);

Is there a "StringToDelegate" that could make this work?

Note that the required delegate type (in this case "Func< List< double >, bool >") is known in advance, both by the software that creates the strings and the one that needs to use them.

Thanks!

Human Wannabe
  • 164
  • 2
  • 10
  • 7
    https://www.strathweb.com/2018/01/easy-way-to-create-a-c-lambda-expression-from-a-string-with-roslyn/ – Amir Popovich Oct 04 '18 at 16:31
  • Thanks Amir! This seems to work right out of the box, however there seems to be some time overhead. Specifically, it takes over 2.5secs to compile the first expression, but it then takes just over 100ms for each following expression. Any ideas on how to make the initial loading faster? – Human Wannabe Oct 04 '18 at 19:39

1 Answers1

0

Thanks to the initial pointer from Amir Popovich, I was able (several hours later) to find the answer. As it was not very straight forward, I will put all the details here for whoever needs this in the future (including myself).

Unfortunately, the Roslyn approach (described here https://www.strathweb.com/2018/01/easy-way-to-create-a-c-lambda-expression-from-a-string-with-roslyn/), although working immediately out of the box, was very slow. I experienced an overhead of approximately 2600ms for compiling the first expression and 100ms for each expression thereafter. In the comments of that page however, one Jochen Kühner pointed out the existence of the System.Linq.Dynamic.Core package (https://github.com/StefH/System.Linq.Dynamic.Core) that could do the same job. This however did not work out of the box, and even the examples in the documentation were producing errors. After some research, I realised that there was a problem in the package available in NuGet, and one Paritosh pointed out the need to also add a newer version of a file directly to my project (see Linq Dynamic ParseLambda not resolving).

So basically to get this to work (at least in .NET Core) you need to:

1) Add the NuGet System.Linq.Dynamic.Core to your project.

2) Go to the following link and get the CSharpSamples.zip from Microsoft:

https://msdn.microsoft.com/en-us/vstudio/bb894665.aspx?f=255&MSPPError=-2147217396

3) Find the file LinqSamples\DynamicQuery\DynamicQuery\Dynamic.cs and copy it into your own project.

With the above, you should have a working environment. Then if you include the following:

using System;
using System.Linq;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Linq.Dynamic;

You can write code like this:

List<List<double>> myList = new List<List<double>>()
{
    new List<double>(){ 1, 25 },
    new List<double>(){ 2, 14 },
    new List<double>(){ 3, 30 }
};

ParameterExpression[] x = new ParameterExpression[] { Expression.Parameter(typeof(List<double>), "x") };
Func<List<double>, bool> adultFilter = (Func<List<double>, bool>) System.Linq.Dynamic.DynamicExpression.ParseLambda(x, null, "x[1] > 18").Compile();
int adults = myList.Count(adultFilter);
Console.WriteLine("Total adults " + adults);

Note that there is a class DynamicExpression in both Linq.Expression & Link.Dynamic, hence the need to provide the full reference and have an extra long line. Also note that the above takes about 30ms to compile & run, with no extra overhead for the first expression.

You can find more details on how to use the Linq.Dynamic library here (although the writer claims the Wiki is only about 80% accurate):

https://github.com/StefH/System.Linq.Dynamic.Core/

I hope that one day the NuGet package will be fixed and the Wiki will be improved, but until then maybe these notes will be of help!

Human Wannabe
  • 164
  • 2
  • 10