1021

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>?

Arsen Khachaturyan
  • 6,472
  • 4
  • 32
  • 36
Richard Nagle
  • 10,764
  • 3
  • 19
  • 16
  • 16
    Func<> will be converted to a method on the c# compiler level ,Expression> will be executed on the MSIL level after compiling the code directly, that is the reason it is faster – Waleed A.K. Aug 28 '16 at 18:05
  • 1
    in addition to the answers, the csharp language specification "4.6 expression tree types" is helpful to cross reference – djeikyb Dec 04 '17 at 23:51
  • For anyone wanting to cross-reference with the C# Language Specification: [Expression Tree Types](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/types#expression-tree-types) – Rae Apr 22 '21 at 00:17

10 Answers10

1209

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:

Expression vs Func larger image

While they both look the same at compile time, what the compiler generates is totally different.

mmx
  • 390,062
  • 84
  • 829
  • 778
  • 105
    So, in other words, an `Expression` contains the meta-information about a certain delegate. – bertl Feb 25 '15 at 13:37
  • 48
    @bertl Actually, no. The delegate is not involved at all. The reason there's any association at all with a delegate is that you can compile the expression *to* a delegate - or to be more precise, compile it to a method and get the delegate to that method as a return value. But the expression tree itself is just data. The delegate does not exist when you use `Expression>` instead of just `Func<...>`. – Luaan Jun 16 '15 at 20:15
  • 2
    You're absolutely right @Luaan. I did not mean to create any artificial relationship between `Expressions` and delegates. My point was related to the original question, i.e. "What does an `Expression>` have and a `Func` not?" I just wanted to summarize the accepted answer in a very brief manner; it may sound a little oversimplified, though. – bertl Jun 17 '15 at 06:26
  • This metadata is useful so that you can convert a C# query into a query in any other language. For example, you could convert C# `StartsWith()` into SQL `LIKE '%etc'` . See http://www.codethinked.com/taking-the-magic-out-of-expression – drizin Jun 28 '16 at 14:04
  • 1
    What makes it a tree? Where are the branches? – Kyle Delaney Jan 13 '17 at 02:47
  • 5
    @Kyle Delaney `(isAnExample) => { if(isAnExample) ok(); else expandAnswer(); }` such expression is an ExpressionTree, branches are created for the If-statement. – Matteo Marciano - MSCP Jan 20 '17 at 14:47
  • 4
    @bertl Delegate is what CPU sees (executable code of one architecture), Expression is what compiler sees (merely another format of source code, but still source code). – codewarrior May 05 '17 at 09:22
  • 6
    @bertl: It might be more accurately summarized by saying that an expression is to a func what a stringbuilder is to a string. It's not a string/func, but it contains the needed data to create one when asked to do so. – Flater Nov 05 '18 at 14:43
388

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.

Chad Hedgcock
  • 9,557
  • 3
  • 32
  • 41
  • 3
    Chad; Please explain this comment a bit more: "Func didn't work because my DbContext was blind to what was actually in the lambda expression to turn it into SQL, so it did the next best thing and iterated that conditional through each row in my table." – JWP Oct 03 '16 at 23:03
  • 2
    >> Func... All you can do is run it. It's not exactly true, but I think that's the point that should be emphasized. Funcs/Actions are to be run, Expressions are to be analyzed (before running or even instead of running). – Konstantin Mar 26 '17 at 15:22
  • 1
    @Chad Is the problem here was that?: db.Set queried all the database table, and after, because .Where(conditionLambda) used the Where(IEnumerable) extension method, which is enumerate on the whole table in the memory. I think you get OutOfMemoryException because, this code tried to load the whole table to the memory (and of course created the objects). Am i right? Thanks :) – Bence Végert Oct 23 '18 at 20:25
  • 1
    I think a simpler explination of @JohnPeters question was that under the covers LinqToSql is turning your lambda expression from the Linq .Where(x => x.Value > 30) to the Sql string "WHERE Value > 30" and passing it along to the database. Expression is the magic juju that lets that happen. – WhiteleyJ Nov 12 '20 at 13:02
  • Is it possible to have a method for entity framework that takes a method with an Func<> but pass in an an object of type Expression> (expr) with the Compile() method... .i.e. - var results = repository.Find(expr.Compile()) ? Or will is suffer the same performance ? – bbqchickenrobot Nov 16 '20 at 05:17
  • 1
    @bbqchickenrobot Types are important - the result of `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. – NetMage Feb 09 '21 at 19:25
112

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)

LSpencer777
  • 1,699
  • 2
  • 13
  • 14
  • +l for explanation. However I get 'The LINQ expression node type 'Invoke' is not supported in LINQ to Entities.' and had to use ForEach after fetching the results. – tymtam Apr 29 '13 at 04:52
92

There is a more philosophical explanation about it from Krzysztof Cwalina's book(Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries);

Rico Mariani

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.

Oğuzhan Soykan
  • 2,072
  • 1
  • 15
  • 30
  • 11
    Well put. ie. You need expression when you are expecting your Func to be converted into some sort of query. Ie. you need `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. – Chad Hedgcock Mar 26 '16 at 03:59
  • 1
    So when i am planning for a Vacation, I would use `Expression` but when I am ON vacation it will be `Func/Action` ;) – GoldBishop Nov 07 '17 at 19:42
  • 1
    @ChadHedgcock This was the final piece I needed. Thanks. I have been looking at this for a while, and your comment here made all the study click. – johnny Jan 04 '19 at 16:30
85

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;
  • expression tree can be constructed through lambda expression syntax or through the API syntax;
  • expression tree can be compiled to a delegate Func<T>;
  • the inverse conversion is theoretically possible, but it's a kind of decompiling, there is no builtin functionality for that as it's not a straightforward process;
  • expression tree can be observed/translated/modified through the ExpressionVisitor;
  • the extension methods for IEnumerable operate with Func<T>;
  • the extension methods for IQueryable operate with 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.

Olexander Ivanitskyi
  • 2,122
  • 14
  • 31
  • Nice list, one small note is you mention that the inverse conversion is possible, however an exact inverse is not. Some metadata is lost during the conversion process. However you could decompile it to an Expression tree that produces the same result when compiled again. – Aidiakapi Mar 13 '15 at 19:43
41

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.

PeterFett
  • 3
  • 3
Marc Gravell
  • 927,783
  • 236
  • 2,422
  • 2,784
22

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:

  • Mapping the code to a different environment (ie. C# code to SQL in Entity Framework)
  • Replacing parts of the code in runtime (dynamic programming or even plain DRY techniques)
  • Code validation (very useful when emulating scripting or when doing analysis)
  • Serialization - expressions can be serialized rather easily and safely, delegates can't
  • Strongly-typed safety on things that aren't inherently strongly-typed, and exploiting compiler checks even though you're doing dynamic calls in runtime (ASP.NET MVC 5 with Razor is a nice example)
Luaan
  • 57,516
  • 7
  • 84
  • 100
  • can you elaborate a bit more on no.5 – uowzd01 Oct 25 '15 at 23:09
  • @uowzd01 Just look at Razor - it uses this approach extensively. – Luaan Oct 26 '15 at 08:04
  • @Luaan I am looking for expression serializations but not able to find anything without a limited third party usage. Does .Net 4.5 support expression tree serialization? – vabii Dec 12 '17 at 19:27
  • @vabii Not that I know of - and it wouldn't really be a good idea for the general case. My point was more about you being able to write pretty simple serialization for the specific cases you want to support, against interfaces designed ahead of time - I've done just that a few times. In the general case, an `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. – Luaan Dec 13 '17 at 14:30
21

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.

Andrew Hare
  • 320,708
  • 66
  • 621
  • 623
18

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.

Ian Kemp
  • 24,155
  • 16
  • 97
  • 121
mhenry1384
  • 7,126
  • 4
  • 50
  • 69
  • Does this apply to in-memory query as well? – stt106 Jan 04 '18 at 15:18
  • @stt106 Probably not. – mhenry1384 Jan 06 '18 at 02:54
  • 1
    This is only true if you enumerate the list. If you use GetEnumerator or foreach you will not load the ienumerable fully into memory. – nelsontruran Apr 23 '18 at 20:17
  • 2
    @stt106 When passed to the .Where() clause of a List<>, Expression> gets .Compile() called on it, so Func<> is almost certainly faster. See https://referencesource.microsoft.com/#System.Core/System/Linq/SequenceQuery.cs,6bf428aa1f6b9002,references – NStuke Aug 01 '18 at 18:43
6

Overly simplified here, but Func is a machine, whereas Expression is a blueprint. :D

Xeuron
  • 384
  • 4
  • 12