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

ExpressionParser failed to parse Func type #570

Closed
orcation opened this issue Feb 23, 2022 · 2 comments
Closed

ExpressionParser failed to parse Func type #570

orcation opened this issue Feb 23, 2022 · 2 comments
Labels

Comments

@orcation
Copy link

orcation commented Feb 23, 2022

I was trying to parse a expression string like this:

ParameterExpression p1 = Expression.Parameter(typeof(Customer), "p1");

ParsingConfig config = new ParsingConfig();
config.CustomTypeProvider = new FuncTypeProvider();

var e3 = DynamicExpressionParser.ParseLambda(/*config,*/ new ParameterExpression[] { p1 }, typeof(Func<int, bool>), "(p1.Method()).Invoke(1)");

var result = e3.Compile().DynamicInvoke(new Customer());

And the Customer class looks like this:

public class Customer
{
    public Func<int, bool> Method()
    {
        return x=>x>0;
    }
}

FuncTypeProvider is implemented like this:

public class FuncTypeProvider : IDynamicLinkCustomTypeProvider
{
    private HashSet<Type> _customTypes;
    public HashSet<Type> GetCustomTypes()
    {
        if (_customTypes != null)
            return _customTypes;

        _customTypes = new HashSet<Type>();
        _customTypes.Add(typeof(Func<int, bool>));

        return _customTypes;
    }

    public Dictionary<Type, List<MethodInfo>> GetExtensionMethods()
    {
        throw new NotImplementedException();
    }

    public Type ResolveType(string typeName)
    {
        throw new NotImplementedException();
    }

    public Type ResolveTypeBySimpleName(string simpleTypeName)
    {
        throw new NotImplementedException();
    }
}

Exception occurs when creating e3:
System.Linq.Dynamic.Core.Exceptions.ParseException: 'Expression of type 'Func`2' expected'

Stack trace:

   at System.Linq.Dynamic.Core.Parser.ExpressionParser.Parse(Type resultType, Boolean createParameterCtor)
   at System.Linq.Dynamic.Core.DynamicExpressionParser.ParseLambda(Type delegateType, ParsingConfig parsingConfig, Boolean createParameterCtor, ParameterExpression[] parameters, Type resultType, String expression, Object[] values)
   at System.Linq.Dynamic.Core.DynamicExpressionParser.ParseLambda(ParsingConfig parsingConfig, Boolean createParameterCtor, ParameterExpression[] parameters, Type resultType, String expression, Object[] values)
   at System.Linq.Dynamic.Core.DynamicExpressionParser.ParseLambda(ParsingConfig parsingConfig, ParameterExpression[] parameters, Type resultType, String expression, Object[] values)

Is it because I missed something that should be configured before parsing? Or is it because the lib cannot process a Func type return?

I'm quite a noob here, if there's anything wrong with my expression or the way I express, please let me know. Any help would be appreciated.

@StefH StefH self-assigned this Aug 5, 2022
@StefH StefH added the question label Aug 5, 2022
@StefH StefH removed their assignment Aug 5, 2022
@ademchenko
Copy link

ademchenko commented Aug 17, 2022

  1. The issue is that you are supposed to pass the return type of the lambda but not the lambda itself into the "resultType" parameter.
  2. Consider deriving from DefaultDynamicLinqCustomTypeProvider rather than implementing the interface.
  [Test]
        public void Issue570()
        {
            var p1 = Expression.Parameter(typeof(Customer), "p1");

            var config = new ParsingConfig
            {
                CustomTypeProvider = new FuncTypeProvider()
            };

            var lambda = DynamicExpressionParser.ParseLambda(config, new[] { p1 }, typeof(bool), "p1.Method().Invoke(1)");
            var compiledLambda = lambda.Compile();

            //Actually, you don't need dynamic invoke since the lambda is parsed
            //and you know the actual type of your delegate
            var staticInvoke = ((Func<Customer, bool>)compiledLambda)(new Customer());

            TestContext.WriteLine($"Static invoke: {staticInvoke}");

            //But if, however, you want dynamic invoke it works as well
            var dynamicInvoke = compiledLambda.DynamicInvoke(new Customer());

            TestContext.WriteLine($"Dymamic invoke: {dynamicInvoke}");

        }

        public class Customer
        {
            public Func<int, bool> Method()
            {
                return x => x > 0;
            }
        }

        //Consider deriving form DefaultDynamicLinqCustomTypeProvider rather than implementing the interface
        public class FuncTypeProvider : DefaultDynamicLinqCustomTypeProvider
        {
            public override HashSet<Type> GetCustomTypes()
            {
                var customTypes = base.GetCustomTypes();
                customTypes.Add(typeof(Func<int, bool>));

                return customTypes;
            }
        }

@orcation
Copy link
Author

Hello, @ademchenko
Thank you so much for helping.
I literally confused the "returnType" of p1.Method with p1.Method.Invoke.

@orcation orcation closed this as completed Jan 7, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

No branches or pull requests

3 participants