Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question: Generic and Param based Custom Type Methods Support #386

Closed
joshidp opened this issue Jun 6, 2020 · 18 comments
Closed

Question: Generic and Param based Custom Type Methods Support #386

joshidp opened this issue Jun 6, 2020 · 18 comments
Assignees

Comments

@joshidp
Copy link

joshidp commented Jun 6, 2020

Hello,

Thanks for the awesome work.

I'm using your lib to write json configurable rules. I want to used generic and param based custom type methods as Utility methods. Below is a sample json config snippet.

{"expression": "Utilities.ConvertToArray(\"xyz\",\"abc\")"}

and below is the method with param

 public static string[] ConvertToArray(params string[] values)
        {
            if (values == null)
            {
                return new string[0];
            }

            return values.ToArray();
        }

When I try to call DynamicExpressionParser.ParseLambda method with above expression it fails with an error saying "No method called ConvertToArray found in Utilities". Please not normal method without param works just fine.

I want to create an array but since that was not possible in the expression directly using your lib I tried using the Utility method.

Similarly, generic methods also doesn't work.

Please help in providing a solution.

Thanks

@JonathanMagnan JonathanMagnan self-assigned this Jun 7, 2020
@JonathanMagnan
Copy link
Member

Hello @joshidp ,

Depending on your requirement, I might recommend you our other library instead: https://eval-expression.net/

This library is not free (unless you use only the LINQ part), but allow you to do pretty much anything such as using static method that you have created (You will need to notify our library by Registering the type).

If the only method not supported you want is creating an array, we might add this in this library as we see a value here. However, if you want to go a lot deeper than this library System.Linq.Dynamic.Core will probably not allow it unless our other library (C# Eval Expression) which supports pretty much everything.

Let me know if all you are looking for is creating an array or not.

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

@StefH
Copy link
Collaborator

StefH commented Jun 10, 2020

@joshidp This is possible.

You need to create a static class and a static method. And annotate that class with the DynamicLinqType attribute.

Utils class

[DynamicLinqType]
public static class Utils
{
    public static string[] ConvertToArray(string[] values)
    {
        if (values == null)
        {
            return new string[0];
        }

        return values.ToArray();
    }
}

Usage

public class X
{
  public string[] Values { get; set; }
}

var list = new[] { new X { }, new X { Values = new[] { "a", "b" } } }.AsQueryable();
var result = list.Select(config, "Utils.ConvertToArray(Values)").ToDynamicList<string[]>();

However, these helper methods can only work on Linq to Objects.
It's not possible to use this for Linq to Entities (SQL).

Please let me know if this works for you.

@joshidp
Copy link
Author

joshidp commented Jun 11, 2020

Thanks @StefH for the reply.

If I use your example of Class X the solution works but if I try to use my example I still get an error "System.Linq.Dynamic.Core.Exceptions.ParseException: 'No applicable method 'ConvertToArray' exists in type 'Utils''
"

In you example, Values prop is already a string array but what I am trying to do is pass string param and get the array back. Show below

Utility class

[DynamicLinqType]
   public static class Utils
   {
       public static string[] ConvertToArray(params string[] values)
       {
           if (values == null)
           {
               return new string[0];
           }

           return values.ToArray();
       }
   }

Usage


  var externals = new Dictionary<string, object>
            {
                {"Users", false},
                {"x", new[] { "a", "b", "c" } },
                {"y", 2},
            };

            string query = "Utils.ConvertToArray(\"a\",\"b\")";
            LambdaExpression expression = DynamicExpressionParser.ParseLambda(null, query, externals);
            Delegate del = expression.Compile();
            var result = del.DynamicInvoke();

Please tell how this issue can be resolved.

Thanks! in advance.

@StefH
Copy link
Collaborator

StefH commented Jun 11, 2020

I think the params is not supported, so you can only use string[] values or string value.
Maybe you could just use object value and determine if it's an string or string-array yourself?
But I think that passing \"a\",\"b\" will be detected as 2 separate parameters, and not a params-string-array.

@joshidp
Copy link
Author

joshidp commented Jun 11, 2020

ok, Thanks.

For now I'm thinking to write overloaded methods to return string[], it should suffice for limited set of values.

public static string[] ConvertToArray(string value1, string value2)
public static string[] ConvertToArray(string value1, string value2, string value3)
public static string[] ConvertToArray(string value1, string value2, string value3, string value4)
public static string[] ConvertToArray(string value1, string value2, string value3, string value4, string value5)

Thanks

@joshidp joshidp closed this as completed Jun 11, 2020
@JonathanMagnan
Copy link
Member

Hello @joshidp ,

Thank @StefH for pointing us out the DynamicLinqType, we were not aware of it and seem to be very useful for plenty of scenarios.

The v1.1.3 has been released. The library should now support params parameter (You can pass it like in your example but cannot yet create an array such as new string[] { "a", "b" }).

Let us know if everything works as expected.

@StefH
Copy link
Collaborator

StefH commented Jun 15, 2020

@JonathanMagnan

I think that the original method from @joshidp is still not recognized?

public static string[] ConvertToArray(params string[] values)
        {
            if (values == null)
            {
                return new string[0];
            }

            return values.ToArray();
        }

With

public class X
{
  public string[] Values { get; set; }
}

var list = new[] { new X { }, new X { Values = new[] { "a", "b" } } }.AsQueryable();
var result = list.Select(config, "Utils.ConvertToArray(Values)").ToDynamicList<string[]>();

Still throws:

Unhandled Exception: System.Linq.Dynamic.Core.Exceptions.ParseException: No applicable method 'ConvertToArray' exists in type 'Utils'

@JonathanMagnan
Copy link
Member

You are right, we forget probably the most essential case!

The v1.1.5 has been released

@JimmyPandas
Copy link

@StefH @JonathanMagnan
Hi team, this library is really powerful and I'm really appreciate your awesome work and support. Discussion within this issue has helped me to figure out how to define own custom static function and apply it in dynamic linq to object. However, I am wondering if there is a way we can apply C# extension function.

@JonathanMagnan
Copy link
Member

Hello @JimmyLzy ,

When you say C# extension function, you mean C# extension method right?

Unless I'm wrong, extension methods are not yet supported.

We will look if that's possible or not to support basic scenario at least.

@JimmyPandas
Copy link

JimmyPandas commented Jun 30, 2020

@JonathanMagnan
Yeah I mean c# extension method here. My static function works fine in local. However, when code is installed in ubuntu-18 in cloud, I get exception System.Linq.Dynamic.Core.Exceptions.ParseException: Expression expected. Do you have any ideas what cause this exception?
Thank you,
Jimmy

@JonathanMagnan
Copy link
Member

What do you mean @JimmyLzy by works fine in local.

Unless I'm wrong, the library doesn't support yet extension methods when I checked yesterday.

@JimmyPandas
Copy link

@JonathanMagnan I meant running code in my windows laptop

@JimmyPandas
Copy link

JimmyPandas commented Jul 1, 2020

@JonathanMagnan I managed to get more exception message Expression expected (at index 41). Actually the issue is on our side. I forgot to clear some cache which causes the predicate to be generated incorrectly. It was Executing query field = @0 AND (FilterUtils.WithinXMiles(,@1,@2)) with args GeoCoord,0 0,20. That's why the library can not parse it.

@JonathanMagnan
Copy link
Member

Hello @JimmyLzy ,

Just to let you know that a first version to support the extension method has been made.

We are currently completing the testing phase and a new version should be available within a few days.

@JonathanMagnan
Copy link
Member

Hello @JimmyLzy ,

The v1.1.6 has been released which should now support extension methods.

See those unit tests example: https://github.com/zzzprojects/System.Linq.Dynamic.Core/blob/master/test/System.Linq.Dynamic.Core.Tests/Parser/DynamicLinqTypeTest.cs#L30

Let me know if everything works as expected.

@Feroks
Copy link

Feroks commented Jul 6, 2020

@JonathanMagnan i think it does not work, if extension uses generics.

@JonathanMagnan
Copy link
Member

You are right @Feroks ,

We did it very basic for the first version. We support some simple scenarios.

I'm currently not sure if we wish to go further and support more scenario or redirect people to our other library C# Eval Expression which handle more complex overload resolution.

If you wish we try it, create a new issue with an example of a method and I will ask my developer to look at it. I believe it could be possible to handle one generic parameter (which is more than enough for a lot of cases) but supporting multiple generic parameters would be too long for now.

dogguts added a commit to dogguts/System.Linq.Dynamic.Core that referenced this issue Jun 8, 2021
dogguts added a commit to dogguts/System.Linq.Dynamic.Core that referenced this issue Jun 8, 2021
dogguts added a commit to dogguts/System.Linq.Dynamic.Core that referenced this issue Jun 9, 2021
* support for generic (static) methods, thus also support for extension methods
(related to zzzprojects#386 )

* support for generic (static) methods, thus also support for extension methods
(related to zzzprojects#386 )
StefH pushed a commit that referenced this issue Aug 20, 2021
#517)

* support for generic (static) methods, thus also support for extension methods
(related to #386 )

* support for generic (static) methods, thus also support for extension methods
(related to #386 )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

5 participants