LINQ: How to force a link based on values?

I want to provide a set of filters for the user to select, and each filter will correspond to Expression<Func<X, bool>> . Thus, I could take a dynamic list of available elements ("Joe", "Steve", "Pete", etc.) and create a set of "hard-coded" filters based on these names and let the user choose which filter he wants to use . My problem is that even when I try to β€œhardcode” my expression based on a string value from a dynamic list, the expression still saves the value as, it seems to me, a property that hangs an anonymous type (and I don’t know how to serialize anon. Type). Sorry if this is confusing, I'm not quite sure how to articulate it.

Here is my sample code:

  public class Foo { public string Name { get; set; } } static void Main(string[] args) { Foo[] source = new Foo[] { new Foo() { Name = "Steven" } , new Foo() { Name = "John" } , new Foo() { Name = "Pete" }, }; List<Expression<Func<Foo, bool>>> filterLst = new List<Expression<Func<Foo, bool>>>(); foreach (Foo f in source) { Expression<Func<Foo, bool>> exp = x => x.Name == f.Name; filterLst.Add(exp); } } } 

My problem is that when I look, when I look at the body of my expression, it reads as follows:

 (x.Name = value(ConsoleApplication1.Program+<>c__DisplayClass3).value) 

When what I really want, for the first we read like this:

 (x.Name = "Steven") 

(if I change my code to this, instead, exactly what I get:

  Expression<Func<Foo, bool>> exp = x => x.Name == "Steven"; 

)

I tried to force my value to a local string value before inserting it into the expression, but it doesn't seem to help:

  List<Expression<Func<Foo, bool>>> filterLst = new List<Expression<Func<Foo, bool>>>(); foreach (Foo f in source) { string value = f.Name; Expression<Func<Foo, bool>> exp = x => x.Name == value; filterLst.Add(exp); } 

I don’t understand why (or indeed even how) it is still looking at some kind of anonymous type, even when I use a local variable declared in a string. Is there any way to make this work the way I want it?

+6
c # linq
source share
2 answers

Anon-type is the type actually created by the compiler that it uses to capture variables. With delegates, you can crack this by manually grabbing, but not with lambda expressions compiled for expression trees.

Two options:

  • build an expression tree explicitly on code through Expression.Constant, etc.
  • learn how to handle types of annonas

The latter is not so bad; they are usually MemberExpression, although I have some code that covers everything that covers this in detail. I can also give examples of building an expression tree, but at the moment I am not on a PC, and it is not suitable for inputting an iPod ...

From a brief reading of the question, I would look at the first option more than the second.

Oh, and be careful; the first foreach code in the question seems susceptible to the infamous l-value capture problem;)


Edit: I found a PC, p

  var param = Expression.Parameter(typeof(Foo), "x"); var body = Expression.Equal( Expression.PropertyOrField(param, "Name"), Expression.Constant(f.Name, typeof(string))); var exp = Expression.Lambda<Func<Foo, bool>>(body, param); filterLst.Add(exp); 
+7
source share

Mark Gravel's answer is correct, and here is how you make your first choice:

 var filters = from f in source let param = Expression.Parameter(typeof(Foo),"x") select Expression.Lambda<Func<Foo, bool>>( Expression.Equal( Expression.Property(param, "Name"), Expression.Constant(f.Name)), param); 

But this is usually not required. The second for loop example should work with all major LINQ providers. Is there a reason you need an expression to use constants?

+4
source share

All Articles