System.Linq.Dynamic.Core icon indicating copy to clipboard operation
System.Linq.Dynamic.Core copied to clipboard

ExpressionPromoter.Promote Limitations to Detect plausible method matches

Open joshidp opened this issue 5 years ago • 2 comments

Hi,

I am highlighting one constraint/issue which is little annoying and could be improved upon.

When I use String.Join method below are the possible overloads which can be called.


+		[0]	{System.String Join(System.String, System.String[])}
+		[1]	{System.String Join(System.String, System.Object[])}
+		[2]	{System.String Join(System.String, System.Collections.Generic.IEnumerable`1[System.String])}
+		[3]	{System.String Join(System.String, System.String[], Int32, Int32)}
+		[4]	{System.String Join[T](System.String, System.Collections.Generic.IEnumerable`1[T])}

Now in ExpressionPromoter.Promote class of your lib the type match is exact for IEnumerable types.

For example below are the two types, one for string enumerable and another one is int enumerable obj.


{Name = "IEnumerable`1" FullName = "System.Collections.Generic.IEnumerable`1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"}

{Name = "IEnumerable`1" FullName = "System.Collections.Generic.IEnumerable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"}

So ExpressionPromoter.Promote returns the expression for string enumerable but for int enumerable it returns null, due to which we get an error saying no method Join found.

Whereas normally(in c#) when we use int enumerable obj with string.Join it works perfectly, probably because it's matching with the below two types.


+		[1]	{System.String Join(System.String, System.Object[])}
+		[4]	{System.String Join[T](System.String, System.Collections.Generic.IEnumerable`1[T])}

I would like to know if in your lib can you please make your best method search approach to be more wider which can detect generic methods too? String.Join is just an example, this change can be very useful for many methods.

Code to reproduce the issue:

Works

 var strArray = new[] { "1","2","3","4"};
var x = new List<ParameterExpression>();
x.Add(Expression.Parameter(strArray.GetType(), "strArray"));

  var config = new ParsingConfig();
 string query = "string.Join(\",\" , strArray)";

  var e = DynamicExpressionParser.ParseLambda(config, x.ToArray(), null, query);
   Delegate del = e.Compile();
    var result = del.DynamicInvoke(strArray);

Doesn't Work

 var intArray = new[] { 1,2,3,4};
var x = new List<ParameterExpression>();
x.Add(Expression.Parameter(intArray.GetType(), "intArray"));

  var config = new ParsingConfig();
 string query = "string.Join(\",\" , intArray)";

  var e = DynamicExpressionParser.ParseLambda(config, x.ToArray(), null, query);
   Delegate del = e.Compile();
    var result = del.DynamicInvoke(intArray);

Thanks!

joshidp avatar Jun 12 '20 07:06 joshidp

Hello @joshidp ,

Thank you for reporting,

We will look at it probably this weekend.

Best Regards,

Jon


Performance Libraries context.BulkInsert(list, options => options.BatchSize = 1000); Entity Framework ExtensionsEntity Framework ClassicBulk OperationsDapper Plus

Runtime Evaluation Eval.Execute("x + y", new {x = 1, y = 2}); // return 3 C# Eval FunctionSQL Eval Function

JonathanMagnan avatar Jun 12 '20 14:06 JonathanMagnan

Hello @joshidp ,

We looked at this issue and in the short term, I don't think we will improve the method overload resolution. Way too much code is involved to make it works or improve it. A major code revamps would be required which will come without a doubt a major version if we do it.

If we want to make it works correctly, we will have to bring back the method overload resolution we did in our other library (C# Eval Expression) which took us weeks to make it works (and still is not 100% perfect but close enough).

So, if you wish a better method resolution, I recommend you to try https://eval-expression.net/ (free for LINQ part). Otherwise, I don't think anything will be done in short term.

Best Regards,

Jon


Performance Libraries context.BulkInsert(list, options => options.BatchSize = 1000); Entity Framework ExtensionsEntity Framework ClassicBulk OperationsDapper Plus

Runtime Evaluation Eval.Execute("x + y", new {x = 1, y = 2}); // return 3 C# Eval FunctionSQL Eval Function

JonathanMagnan avatar Jun 15 '20 19:06 JonathanMagnan

https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/731

StefH avatar Aug 08 '23 07:08 StefH