views:

44

answers:

1

We have an object and we want to build a linq query based on that object on the fly. This linq statement is equivalent to what we want to build:

Expression<Func<Sample, bool>> linqExpression 
            = x => x.Child == itemToCompare.Child;

We can't quite come up with the right expression to build the itemToCompare.Child part. Here's what we have so far:

var param = Expression.Parameter(typeof(T), "x");
var key = itemToCompare.GetType().GetProperty("Child");
var rhsConstant = Expression.Constant(item);
var innerLambda = Expression.Lambda<Func<T>>(rhsConstant, 
            new ParameterExpression[0]);
var rhsMemberAccess = Expression.MakeMemberAccess(innerLambda, key);
body = Expression.Equal(lhsPropertyAccess, rhsMemberAccess);
var lambda = Expression.Lambda<Func<T, bool>>(body, param);

The expression tree for our hand-built query looks like:

Lambda Expression: x => (x.Child = value(SampleTests+Sample))
Expression Body: (x.Child = value(SampleTests+Sample))
Parameter 0: 'x', Type: Sample
NodeType: Lambda
   Left Lambda Expression: x.Child
   Left NodeType: MemberAccess
      Lambda Expression: x
      Expression Member: Sample Child
      NodeType: Parameter
         -- a parameter expression
   Right Lambda Expression: value(SampleTests+Sample)
   Right NodeType: Constant
      NodeType: Constant
      Value: SampleTests+Sample

The expression tree for the actual lambda looks like:

Lambda Expression: x => (x.Child = value(SampleTests+<>c__DisplayClass15).itemToCompare.Child)
Expression Body: (x.Child = value(SampleTests+<>c__DisplayClass15).itemToCompare.Child)
Parameter 0: 'x', Type: Sample
NodeType: Lambda
   Left Lambda Expression: x.Child
   Left NodeType: MemberAccess
      Lambda Expression: x
      Expression Member: Sample Child
      NodeType: Parameter
         -- a parameter expression
   Right Lambda Expression: value(SampleTests+<>c__DisplayClass15).itemToCompare.Child
   Right NodeType: MemberAccess
      Lambda Expression: value(SampleTests+<>c__DisplayClass15).itemToCompare
      Expression Member: Sample Child
      NodeType: MemberAccess
         Lambda Expression: value(SampleTests+<>c__DisplayClass15)
         Expression Member: Sample itemToCompare
         NodeType: Constant
            NodeType: Constant
            Value: SampleTests+<>c__DisplayClass15

Edit:

We think this works out to

Expression<Func<Sample, bool>> linqExpression 
            = x => x.Child == (()=>itemToCompare).Child;

which is what we're trying to reproduce in our expression.

Ultimately the goal is to produce an Expression where the Child values are compared using their Type's .Equals() method.

Thanks!

+1  A: 

You're getting confused by the "inner lambda". There's only one lambda expression:

var param = Expression.Parameter(typeof(Sample), "x");
var key = itemToCompare.GetType().GetProperty("Child");
var rhs = Expression.MakeMemberAccess(Expression.Constant(itemToCompare), key);
var lhs = Expression.MakeMemberAccess(param, key);
var body = Expression.Equal(lhs, rhs);
var lambda = Expression.Lambda<Func<Sample, bool>>(body, param);
Joe Albahari
Joe, this treats the value of the Child property as a constant. When that value is a reference type it seems to perform a reference comparison instead of calling .Equals() . We need it to call .Equals() .
Handcraftsman
You can call Equals by replacing the body expression with: Expression.Call(typeof(object).GetMethod("Equals",BindingFlags.Static | BindingFlags.Public),lhs,rhs)
Joe Albahari