Linq Expression Syntax and Compilation

I was looking for an example of how to use a specific part of the Telerik grid mesh (ASP.NET MVC3, but this is really not relevant here). They have a piece of code that takes a list of filter descriptions and builds an expression:

System.Linq.Expressions.Expression<Func<MyModel, bool> exp = ExpressionBuilder.Expression<MyModel>(listOfFilters); 

Ok, I think everything is fine. Expression wraps a lambda that works with MyModel to create a bool. Fine. Now their example just drops out, for example, in "Where":

 someList = someList.Where(exp); 

I assume that it should be โ€œheyโ€ to apply this expression to all the elements in the list (which, of course, is a common MyModel). However, VS claims that the code does not compile. I get "No overload Where is or System.Func has a few invalid arguments."

I played with him and found that I could compile an expression that gives a more indecent look

 someList = someList.Where(x => exp.Compile()(x)); 

Which compiles and probably works, but it becomes uncomfortable for me, because now I work clearly beyond what I know.

Is there a reason why (setting the IDE, flag, outdated documentation) the sample approach does not work? Is there an approximate equivalence of my hack and an example? Do I have to structure this hack differently in order to avoid any disgusting problem (for example, not going to compile the expression every time it checks an item in a list, right? I think it is smart enough for that?)

- Edit Yes, it was IEnumerable. I ended up in "all wheres created equal" traps. Thanks everyone!

+4
source share
3 answers

Have you tried just doing

 someList = someList.Where(exp.Compile()); 

If someList is IEnumerable , you will need to use exp.Compile() , which returns Func<MyModel,bool>

If someList is IQueryable , you can use exp.Compile() , or you can use exp , which is Expression<Func<MyModel, bool>>

+2
source

There are two versions of the Where() method: one runs on IEnumerable<T> and accepts Func<T, bool> , and the other runs on IQueryable<T> and accepts Expression<Func<T, bool>> . The reason for this is that IQueryable<T> may represent some remote data, such as a database table. And when you query a table, you donโ€™t want to pass the whole table just to search for the single item you are looking for.

That's why Expression exists: it is used to represent some code, but in a way that can be easily processed and, for example, converted to SQL. Or you can compile it into regular IL code and make it a delegate.

If you want to work with a regular in-memory list (which implements IEnumerable<T> but not IQueryable<T> ), you donโ€™t need expressions at all, you can work with delegates all the time, and your code will probably be simpler and faster.

But if you want to work with Expression s, you can, as you discovered. There are several options:

  • Use the AsQueryable() method . This way you get methods like Where() that work with Expression s.

     someList.AsQueryable().Where(exp) 
  • Compile the expression by calling the Compile() method . It returns a delegate that can be passed directly to Where() .

     someList.Where(exp.Compile()) 

Your attempt will actually compile the expression for each item in the collection, so it will probably have poor performance.

+3
source

What is the type of someList? I assume List<T> . There is no Where extension method that allows Expression<Func<T, bool>> to List<T> or IEnumerable<T> .

You are probably using sending expressions to a query. IQueryable<T> has an Where extension method that allows Expression<Func<T, bool>> . To access it, you will need to do the following

 var someQueryable = someList.AsQueryable().Where(exp); 

This return type will be IQueryable<T> . To put this back in someList, you need to add AsEnumerable() or ToList() depending on the type of someList.

This may not be the best way to do this, but it allows you to use exp as you expected.

+2
source

Source: https://habr.com/ru/post/1398690/


All Articles