|Deep C# - Anonymous Methods, Lambdas And Closures|
|Written by Mike James|
|Monday, 19 September 2016|
Page 3 of 5
Lambdas have made is much easier to use standard types of function within the .NET framework and to make it even easier there are a range of standard pre-defined delegate types.
The Action delegates provide a way to encapsulate a method that does something, i.e. is an "action", returning void and anything from zero to 16 parameters. For example:
To use Action with additional parameters you simply keep specifying them up to the maximum. For example:
The Func delegate works in the same way as the Action delegate but you can also specify a return type in addition to up to sixteen input parameters. The return type is specified as the final type. For example:
Using Action or Func you can create a delegate that can encapsulate almost any lambda expression but notice that there it might still be better to define your own delegate to convey the meaning of what the lambda is supposed to do.
The need to convey a meaning is the motivation behind there being a number of other standard predefined delegates as well as the Action and Func delegates.
For example, a predicate in mathematical logic is a function which evaluates to true or false i.e. a function returning a boolean. The Predicate<T> delegate can be used to wrap a lambda that accepts a single parameter and returns a boolean. That is Predicate <T> is identical to Func<T><bool>.
Similarly the Comparison<T> delegate takes two input parameters, x, y say, of the same type and returns an int that indicates the relative "size" of the two objects - negative means x<y, zero means x=y and positive means x>y. For example
There is also a Converter<Tin,Tout> delegate which represents a method that converts the input type to the output type:
There are lots of other predefined delegates but they rapidly become increasingly specialized like the EventHandler<TEventArgs> delegate.
A statement lambda can have a mix of expressions and statements. However there is a particularly simple form of the lambda that is very common in other languages. An expression lambda" has only a single expression as its body and simply returns the result of the expression:
is an expression lambda that takes x and squares it. Notice that there is only one parameter the parentheses are optional.
The one problem with expression lambdas is that they can look more complicated than they are because they often make use of comparison operators. For example the confusing looking:
defines a lambda expression that returns true if x is smaller than or equal to 10 and false otherwise even though it looks like an expression for crushing an x between itself and 10.
Notice that expression lambdas are ideal for passing short chunks of code, Boolean conditionals for example, to other methods which is what they were designed for.
Expression lambdas are used extensively in the framework classes where there are a number of where the standard delegate types often make this easier. For example the Array type has a static Find method which accepts an array and a predicate and returns the first element that makes the predicate true. For example
returns the first element in MyIntArray that is positive.
In short expression lambdas are ideal for passing functions into methods.
In C#6 they can also be used to define a method. For example:
You can use the same syntax to define a getter only property:
When you use total the expression is evaluated to provide the value.
Slightly more esoteric is the use of a lambda in an indexer:
which will return an instance of MyClass stored in myarray[i] when you use an index on an instance of the class you are defining. For a short but unrealistic example we define the class:
Now we can create an instance and use the indexer:
An expression lambda is also special because it can be converted to an expression tree.
What is an expression tree?
Put simply an expression tree is just an object which contains all of the information contained in the lambda. It is a representation of the function in data.
Why would you want to create an expression tree?
An expression tree can be stored or transmitted to another system where it can be implemented at a later time or remotely. You can think of an expression trees as a data exchange format for lambdas but they also allow you to create lambdas dynamically. You can create an expression tree without using a lambda and then use it to create the method that corresponds to the lambda. That is the expression tree is one way of dynamically generating a method.
The main reason that expression trees were introduced was so that LINQ which makes heavy use of expression lambdas could turn a query into a data structure and send this "over the wire" to a remote server but there are no doubt lots of alternative and innovative uses just waiting to be discovered.
To see expression trees in action, let's take a simple expression lambda and convert it into an Expression object. When an expression lambda is assigned to an Expression variable it is automatically converted to an expression tree. For example:
Notice that you have to specify the delegate type that the Expression object is going to represent - in this case Func<int,int>. Following this instruction ExTree contains a data representation of the expression lambda.
You can explore the expression tree using its methods and properties. For example:
You can apply the method in an expression tree using the Compile method. For example:
stores the expression lambda in MyNewDelegate and then uses it. You can also create the delegate on the fly:
|Last Updated ( Thursday, 22 September 2016 )|