Lambda Expression Tree Parsing

前端 未结 4 1314
慢半拍i
慢半拍i 2020-12-28 18:51

I am trying to use Lambda Expressions in a project to map to a third party query API. So, I\'m parsing the Expression tree by hand.

If I pass in a lambda expression

相关标签:
4条回答
  • 2020-12-28 19:00

    Just been struggling with exactly the same issue, thanks Bevan. On an extension, the following is a generic pattern you can use to extract the value (using this in my query engine).

        [TestFixture]
    public class TestClass
    {
        [Test]
        public void TEst()
        {
            var user = new User {Id = 123};
            var idToSearch = user.Id;
            var query = Creator.CreateQuery<User>()
                .Where(x => x.Id == idToSearch);
        }
    }
    
    public class Query<T>
    {
        public Query<T> Where(Expression<Func<T, object>> filter)
        {
            var rightValue = GenericHelper.GetVariableValue(((BinaryExpression)((UnaryExpression)filter.Body).Operand).Right.Type, ((BinaryExpression)((UnaryExpression)filter.Body).Operand).Right);
            Console.WriteLine(rightValue);
            return this;
        }
    }
    
    internal class GenericHelper
    {
        internal static object GetVariableValue(Type variableType, Expression expression)
        {
            var targetMethodInfo = typeof(InvokeGeneric).GetMethod("GetVariableValue");
            var genericTargetCall = targetMethodInfo.MakeGenericMethod(variableType);
            return genericTargetCall.Invoke(new InvokeGeneric(), new[] { expression });
        }
    }
    
    internal class InvokeGeneric
    {
        public T GetVariableValue<T>(Expression expression) where T : class
        {
            var accessorExpression = Expression.Lambda<Func<T>>(expression);
            var accessor = accessorExpression.Compile();
            return accessor();
        }
    }
    
    0 讨论(0)
  • 2020-12-28 19:10

    To get the actual value, you need to apply the logic of the expression tree to whatever context you've got.

    The whole point of expression trees is that they represent the logic as data rather than evaluating the expression. You'll need to work out what the lambda expression truly means. That may mean evaluating some parts of it against local data - you'll need to decide that for yourself. Expression trees are very powerful, but it's not a simple matter to parse and use them. (Ask anyone who's written a LINQ provider... Frans Bouma has bemoaned the difficulties several times.)

    0 讨论(0)
  • 2020-12-28 19:20

    Remember that when you're dealing with the lambda expression as an expression tree, you don't have executable code. Rather you have a tree of expression elements, that make up the expression you wrote.

    Charlie Calvert has a good post that discusses this in detail. Included is an example of using an expression visualiser for debugging expressions.

    In your case, to get the value of the righthand side of the equality expression, you'll need to create a new lambda expression, compile it and then invoke it.

    I've hacked together a quick example of this - hope it delivers what you need.

    public class Class1
    {
        public string Selection { get; set; }
    
        public void Sample()
        {
            Selection = "Example";
            Example<Book, bool>(p => p.Title == Selection);
        }
    
        public void Example<T,TResult>(Expression<Func<T,TResult>> exp)
        {
            BinaryExpression equality = (BinaryExpression)exp.Body;
            Debug.Assert(equality.NodeType == ExpressionType.Equal);
    
            // Note that you need to know the type of the rhs of the equality
            var accessorExpression = Expression.Lambda<Func<string>>(equality.Right);
            Func<string> accessor = accessorExpression.Compile();
            var value = accessor();
            Debug.Assert(value == Selection);
        }
    }
    
    public class Book
    {
        public string Title { get; set; }
    }
    
    0 讨论(0)
  • 2020-12-28 19:25

    I'm not sure I understand. Where are you "seeing" that? Is that at design-time or run-time? Lambda expressions can be thought of essentially as anonymous delegates, and will operate with deferred execution. So you shouldn't expect to see the value assigned until after execution has passed that line, obviously.
    I don't think that's really what you mean though... if you clarify the question a bit maybe I can help :)

    0 讨论(0)
提交回复
热议问题