I understand lambdas and the Func
and Action
delegates. But expressions
stump me.
In what circumstances would you use an Expression<Func<T>>
rather than a plain old Func<T>
?
I understand lambdas and the Func
and Action
delegates. But expressions
stump me.
In what circumstances would you use an Expression<Func<T>>
rather than a plain old Func<T>
?
When you want to treat lambda expressions as expression trees and look inside them instead of executing them. For example, LINQ to SQL gets the expression and converts it to the equivalent SQL statement and submits it to server (rather than executing the lambda).
Conceptually, Expression<Func<T>>
is completely different from Func<T>
. Func<T>
denotes a delegate
which is pretty much a pointer to a method and Expression<Func<T>>
denotes a tree data structure for a lambda expression. This tree structure describes what a lambda expression does rather than doing the actual thing. It basically holds data about the composition of expressions, variables, method calls, ... (for example it holds information such as this lambda is some constant + some parameter). You can use this description to convert it to an actual method (with Expression.Compile
) or do other stuff (like the LINQ to SQL example) with it. The act of treating lambdas as anonymous methods and expression trees is purely a compile time thing.
Func<int> myFunc = () => 10; // similar to: int myAnonMethod() { return 10; }
will effectively compile to an IL method that gets nothing and returns 10.
Expression<Func<int>> myExpression = () => 10;
will be converted to a data structure that describes an expression that gets no parameters and returns the value 10:
While they both look the same at compile time, what the compiler generates is totally different.
Expression
contains the meta-information about a certain delegate. –
Crim Expression<Func<...>>
instead of just Func<...>
. –
Presley Expressions
and delegates. My point was related to the original question, i.e. "What does an Expression<Func<T>>
have and a Func<T>
not?" I just wanted to summarize the accepted answer in a very brief manner; it may sound a little oversimplified, though. –
Crim StartsWith()
into SQL LIKE '%etc'
. See codethinked.com/taking-the-magic-out-of-expression –
Omphale (isAnExample) => { if(isAnExample) ok(); else expandAnswer(); }
such expression is an ExpressionTree, branches are created for the If-statement. –
Stylistic I'm adding an answer-for-noobs because these answers seemed over my head, until I realized how simple it is. Sometimes it's your expectation that it's complicated that makes you unable to 'wrap your head around it'.
I didn't need to understand the difference until I walked into a really annoying 'bug' trying to use LINQ-to-SQL generically:
public IEnumerable<T> Get(Func<T, bool> conditionLambda){
using(var db = new DbContext()){
return db.Set<T>.Where(conditionLambda);
}
}
This worked great until I started getting OutofMemoryExceptions on larger datasets. Setting breakpoints inside the lambda made me realize that it was iterating through each row in my table one-by-one looking for matches to my lambda condition. This stumped me for a while, because why the heck is it treating my data table as a giant IEnumerable instead of doing LINQ-to-SQL like it's supposed to? It was also doing the exact same thing in my LINQ-to-MongoDb counterpart.
The fix was simply to turn Func<T, bool>
into Expression<Func<T, bool>>
, so I googled why it needs an Expression
instead of Func
, ending up here.
An expression simply turns a delegate into a data about itself. So a => a + 1
becomes something like "On the left side there's an int a
. On the right side you add 1 to it." That's it. You can go home now. It's obviously more structured than that, but that's essentially all an expression tree really is--nothing to wrap your head around.
Understanding that, it becomes clear why LINQ-to-SQL needs an Expression
, and a Func
isn't adequate. Func
doesn't carry with it a way to get into itself, to see the nitty-gritty of how to translate it into a SQL/MongoDb/other query. You can't see whether it's doing addition or multiplication or subtraction. All you can do is run it. Expression
, on the other hand, allows you to look inside the delegate and see everything it wants to do. This empowers you to translate the delegate into whatever you want, like a SQL query. Func
didn't work because my DbContext was blind to the contents of the lambda expression. Because of this, it couldn't turn the lambda expression into SQL; however, it did the next best thing and iterated that conditional through each row in my table.
Edit: expounding on my last sentence at John Peter's request:
IQueryable extends IEnumerable, so IEnumerable's methods like Where()
obtain overloads that accept Expression
. When you pass an Expression
to that, you keep an IQueryable as a result, but when you pass a Func
, you're falling back on the base IEnumerable and you'll get an IEnumerable as a result. In other words, without noticing you've turned your dataset into a list to be iterated as opposed to something to query. It's hard to notice a difference until you really look under the hood at the signatures.
Compile()
will be a Func<>
so you are passing a Func<>
to the Find
method - no Expression
is involved. So your performance will be terrible. –
Kaslik There is a more philosophical explanation about it from Krzysztof Cwalina's book(Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries);
Edit for non-image version:
Most times you're going to want Func or Action if all that needs to happen is to run some code. You need Expression when the code needs to be analyzed, serialized, or optimized before it is run. Expression is for thinking about code, Func/Action is for running it.
database.data.Where(i => i.Id > 0)
to be executed as SELECT FROM [data] WHERE [id] > 0
. If you just pass in a Func, you've put blinders on your driver and all it can do is SELECT *
and then once it's loaded all of that data into memory, iterate through each and filter out everything with id > 0. Wrapping your Func
in Expression
empowers the driver to analyze the Func
and turn it into a Sql/MongoDb/other query. –
Chaste Expression
but when I am ON vacation it will be Func/Action
;) –
Delitescent An extremely important consideration in the choice of Expression
vs Func
is that IQueryable
providers like LINQ to Entities can 'digest' what you pass in an Expression
, but will ignore what you pass in a Func
. I have two blog posts on the subject:
More on Expression vs Func with Entity Framework and Falling in Love with LINQ - Part 7: Expressions and Funcs (the last section)
I'd like to add some notes about the differences between Func<T>
and Expression<Func<T>>
:
Func<T>
is just a normal old-school MulticastDelegate;Expression<Func<T>>
is a representation of lambda expression in form of expression tree;Func<T>
;ExpressionVisitor
;Func<T>
;Expression<Func<T>>
.There's an article which describes the details with code samples:
LINQ: Func<T> vs. Expression<Func<T>>.
Hope it will be helpful.
LINQ is the canonical example (for example, talking to a database), but in truth, any time you care more about expressing what to do, rather than actually doing it. For example, I use this approach in the RPC stack of protobuf-net (to avoid code-generation etc) - so you call a method with:
string result = client.Invoke(svc => svc.SomeMethod(arg1, arg2, ...));
This deconstructs the expression tree to resolve SomeMethod
(and the value of each argument), performs the RPC call, updates any ref
/out
args, and returns the result from the remote call. This is only possible via the expression tree. I cover this more here.
Another example is when you are building the expression trees manually for the purpose of compiling to a lambda, as done by the generic operators code.
When using LINQ-to-SQL, passing Func<>
s into Where()
or Count()
is bad. Real bad. If you use a Func<>
then it calls the IEnumerable
LINQ stuff instead of IQueryable
, which means that whole tables get pulled in and then filtered. Expression<Func<>>
is significantly faster because it performs the filtering on the SQL server - especially so if you are querying a database that lives another server.
The primary reason is when you don't want to run the code directly, but rather, want to inspect it. This can be for any number of reasons:
Expression
can be just as impossible to serialize as a delegate, since any expression can contain an invocation of an arbitrary delegate/method reference. "Easy" is relative, of course. –
Presley You would use an expression when you want to treat your function as data and not as code. You can do this if you want to manipulate the code (as data). Most of the time if you don't see a need for expressions then you probably don't need to use one.
Overly simplified here, but Func
is a machine, whereas Expression
is a blueprint. :D
It’s good to know you can use Func<TEntity, bool>
with AsQueryable()
extension method like Expression<Func<TEntity, bool>>
.
Func<App, bool> filter = x => x.Alias.Contains("gan");
var query = dbSet.Where(filter).AsQueryable();
The query will not be executed until you use the execution methods like Count()
or ToList()
.
Here is my 2 cents...
Func<T>
= A delegate/method that just gets executed, that all.Expression<Func<T>>
= It gets converted to another form. For example, LINQ to Entities where the expression is converted to the equivalent SQL queries.Imagine it in a way that both look similar but the Expression is like a data structure and has the power of reflection. The compiler literally knows everything about it's signature and it's body (similar to class reflection). Using this knowledge, the expression is converted to some other form like LINQ is converted to SQL queries.
Now, there is another angle to it which deals with IQueryable behavior. It is recommended that you always pass Expression
to Where
or Count
method of LINQ so that your query filter runs on the SQL server instead of pulling data in memory and then filtering it.
© 2022 - 2024 — McMap. All rights reserved.