What are lambda expressions?
Lambda expressions are those of type A going to B, meaning primarily a transformation. In C#, there are constant, and multiparametrized Lambdas.
In C#, a lambda expression can be converted to:
- one
Delegate
: is a compiled method, which can be executed, and passed as if it were a variable to whoever needs it. Also called anonymous methods, because they do not have their own identifier.
- one
Expression<>
representing a tree of expressions denoting in data structure form the transformation representing the expression lambda.
Use in the form of Delegate
When converted to a delegate, the lambda can be passed as if it were a variable. A lambda produces a delegate of a specific type depending on the context in which it is created.
The calls below generate delegates of different types:
// delegate gerado do tipo Func<string, bool>
Func<string, bool> func = s => s == null;
// delegate gerado do tipo Predicate<string>
Predicate<string> pred = s => s == null;
Thus each delegate of distinct type can be passed as if it were a common variable, being possible to call these methods so:
pred("string to test");
All delegates, regardless of the specific type, inherit from the class Delegate
.
Closures in delegates
Lambdas can present in its contents, variables present in the method that builds it, trapping this variable, in the form of a reference to it. This is also possible when building inline delegates.
int i = 0;
Action incrementa = () => i++;
incrementa();
// neste ponto a variável i, terá seu valor incrementado
This is a very powerful tool, and also dangerous, especially when used in loops, using the value of the iteration variable.
var listFunc = new Func<int>[10];
for (int it = 0; it < 10; it++)
listFunc[it] = () => it;
// todos os elementos de listFunc retornam 10
// pois a variável it, neste ponto vale 10,
// e todos os delegates referenciam a mesma variável
Use in the form of Expression
When talking about lambda expression, it is common to pass beaten by this way of using them, but that is widely used by frameworks like the EntityFramework
and the MVC
, both from Microsoft.
LINQ supports the interface IQueryable
, which is based on the use of data structure transforms, which it analyzes in order to create a query that can be executed in the database.
Just as these libraries do, it is possible to read this data structure generated from a lambda expression, using the classes present in the namespace System.Linq.Expressions.
In addition, these Ambles in the form of Expression
can be copied and modified, and then compiled, being one of the ways to be generated dynamically executable code. It is also possible to create an expression tree from scratch, dynamically generating integer methods, using the method Compile, present in the class Expression<T>
.
Closures in expression trees (Expression Trees)
Expression Trees can, as well as delegates, have references to context variables in their code. Thus, the reference to the variable is trapped in a node of the expression tree, which allows reading the value of that variable, and maintaining the semantics when compiling this expression tree.
Miguel, closures are not unique to lambda expressions. Anonymous methods also have this feature.
– Paulo Morgado
@The way I said, it really looked like this is the only way to make closures... I’ll edit it. Thanks!
– Miguel Angelo
Great explanation, Miguel.
– Diogo Moreira