Expression> vs FUNC
Both types of types: Expression<Func<T>> and Func<T> are very similar and could be used for the same type of tasks. I will try to dispel any doubts, when to use expressions or when just functions.
Let’s begin with Func<TResult> type. There is simple shortage encapsulation for delegate type taking no argument and returns value of type TResult. You can define this delegate explicitly:
public delegate TResult Func<in T, out TResult>(T arg)
There are also types like Func<T, TResult>, Func<T1, T2, TResult>, … which differ only with number of input parameters.
Full list of encapsulated delegates is below, but we don’t describe it more detailed:
We can define Func both using lambda and by assigning other function
public int ExternalFunction { return 12; } Func<int> func1 = () => 12; Func<int> func2 = ExternalFunction;
Similarly we can define Expression<Func<T>>
Expression<Func<int>> func1 = () => 12;
but the behavior of this two object is different. The Expression type store additionally information (in a tree data structure) about what specific lambda expression does. Thanks to this information it could be possible to process this information and execute this function behavior in different way.
Entity Framework
The difference described above could be well presented in Entity Framework context. If we want to access some data in DbContext we refer to DbSet collection, where we can use Where methods.
This Where methods have different definitions:
IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate); IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate);
As you can notice, there are two differences in definitions. The first one uses Func and operates on IEnumerable<T> collection, but the second one uses Expression and works on IQuerable<T>.
This example shows that using the Expression type Entity Framework can translate function into SQL query and return IQuerable object, so we can add additional query conditions to this query. By using Func type condition, all dataset will be loaded from database and filtering will be done in .NET application.
Conversions
To convert Expression<Func<T>> to Func<T> you can use Compile method
Func<T> func = expressionFunc.Compile();