17

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 like:

p => p.Title == "title"

everything works.

However, if my lambda expression looks like:

p => p.Title == myaspdropdown.SelectedValue

Using the .NET debugger, I don't see the actual value of that funciton. Instead I see something like:

p => p.Title = (value(ASP.usercontrols_myaspusercontrol_ascx).myaspdropdown.SelectedValue)

What gives? And when I try to grab the right side of the expression as a string, I get (value(ASP.usercontrols_myaspusercontrol_ascx).myaspdropdown.SelectedValue) instead of the actual value. How do I get the actual value?

3
  • I think the issue is (and I'm not an expert with Expressions, so this isn't an answer) is that the expression isn't a lambda; it describes the data you wish to retrieve. It isn't executed, its interpreted. Commented Oct 26, 2008 at 19:20
  • That means that the value isn't substituted for your expression at runtime, its set permanently at compile time. In order to get the value, the code interpreting the lambda would have to understand the concept of the user control and how to extract it Commented Oct 26, 2008 at 19:22
  • And unless the code that is interpreting the expression has access to your conntrol and is coded to do this, it isn't possible. If the code has an overload or another method that does the same thing, but takes actual values, you can use that and a lambda to retrieve the value at runtime. Commented Oct 26, 2008 at 19:23

5 Answers 5

21

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; }
}
Sign up to request clarification or add additional context in comments.

Comments

1

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.)

1 Comment

hi john - maybe this question is clearer: stackoverflow.com/questions/238765/…
0

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();
    }
}

1 Comment

Rather than using your reflection to call InvokeGeneric, what I would do is Expression<Func<object>>(Expression.Convert(expression, typeof(object))).Compile()
0

When the C# compiler encounters some number of captured variables, the compiler will implement this high level language feature using the low level features of IL;

  • a new class is defined to manage the new lifetime of these variables on the heap
  • the current values of these variables are assigned as fields of the class
  • an Expression.Constant is created to represent this instance in the expression tree

Essentially;

bool value = true;
Expression<Func<bool>> x = () => value;

Becomes;

[CompilerGenerated]
private sealed class <>c__DisplayClass0_0
{
    public bool value;
}

<>c__DisplayClass0_0 <>c__DisplayClass0_ = new <>c__DisplayClass0_0();
<>c__DisplayClass0_.value = true;
Expression<Func<bool>> x = Expression.Lambda<Func<bool>>(
    Expression.Field(
        Expression.Constant(<>c__DisplayClass0_, typeof(<>c__DisplayClass0_0)),
        /* IL shortcut for typeof(T).GetField(...) */
    ),
    Array.Empty<ParameterExpression>()
);

You can write an ExressionVisitor to recursively locate any MemberExpression, where the .Expression is a constant, and replace that node in the tree with the current value of the field or property.

Attempting to compile that member expression, might work for some valid expressions. But wont work for all of them. Anything with a mixture of captured variables and expression parameters will probably fail. eg x => capturedLocal.SomeList[x.Index];. But then, you wouldn't be able to pass such an expression to an external query provider anyway.

Comments

-1

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 :)

2 Comments

updated question. it's in the debugger [and also when i try to grab the right side of the expression]
@Grank: Lambda expressions can be converted into either expression trees or delegates. It sounds like you're thinking of the conversion into delegates.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.