Deep C# - Anonymous Methods, Lambdas And Closures
Written by Mike James   
Monday, 19 September 2016
Article Index
Deep C# - Anonymous Methods, Lambdas And Closures
From Anonymous Methods to Lamdas
Expressions Lambda to Expression Trees
Closure
Two Patterns for Closure

Anonymous methods

The idea of an anonymous method allows you to fuse the identity of the delegate with the function it wraps.

The syntax is easy, you simply use the delegate keyword to stand in for the name of the function you are trying to wrap and follow it by a definition of that function. Notice that this means that you don't have to create a separate method that has a life of its own that you then wrap in the delegate - this also saves having to give the method a name.

For example, we can create an instance of MyHelloDelegateType:

MyHelloDelegateType MyHelloDelegate1=delegate(){
 MessageBox.Show("Hello From a Delegate");
};

MyHelloDelegate1();

One identifier fewer might not seem much of a victory but now we can recast the code to express the fact that the delegate type is really about the signature and the delegate instance is about what actually happens by renaming the delegate “Hello” i.e. the name that we probably would have assigned the method:

MyHelloDelegateType1 Hello = delegate(){
 MessageBox.Show("Hello From a Delegate");
};

Hello();

You can specify parameters in the function definition by treating the keyword “delegate” as if it was the function’s name. For example:

MyHelloDelegateType2 Hello2 = delegate(string Msg){
 MessageBox.Show(Msg);
};

However for this to work we need to define another delegate type that matches the new signature:

delegate void MyHelloDelegateType2(string MyString);

Notice that the identifier used as the parameter in the type definition doesn’t carry any meaning – it’s just there for the syntax.

Perhaps the C style signature specification:

delegate void MyHelloDelegateType2(string);

would be better but notice, this doesn’t work in C# .

With the type defined we can now call the delegate in the usual way:

Hello2("Hello delegate 2");

The situation is a little more complicated than this simple example suggests.

In fact the anonymous method doesn’t have to match the signature of the delegate type exactly.

As long as the delegate type has no out parameters then the anonymous method can be defined with no parameters.

For example the following is perfectly legal even though the delegate type specifies a single string parameter:

MyHelloDelegateType2 Hello3 = delegate() {
 MessageBox.Show("Default message!");
};

However you still have to call the delegate with the correct signature:

Hello3("dummy");

The parameter supplied is simply thrown away. You can see why this approach doesn’t work without parameters. If there is an out parameter defined, where would the return value come from?

Using anonymous methods

So what are anonymous methods good for?

They certainly save one level of naming confusion but in some cases they can remove the need for any new names at all.

For example, consider the Find method of the Array object defined as:

public static T Find<T> (T[] array,Predicate<T> match)

The Predicate delegate is defined as:

public delegate bool Predicate<T> (T obj)

Without anonymous methods you would have to define a Predicate method, wrap in a delegate and pass it to the Find method.

With anonymous method it can be as simple as:

int result = Array.Find(A,
        delegate(int x) {return (x < 0);});

In short, anonymous methods are good for short functions that you want to use “at once”, often as a parameter within a method call.

However in modern C# lambdas provide a simpler way of doing the same job and more. They work in the same way as anonymous methods but provide a neater way of writing the code.

 

Banner

 

Statement Lambdas 

Lambdas sound esoteric; the name comes from lambda calculus which is important in computer science. You don't need to worry about theory because lambdas solve a very practical problem.

There are two slight variations on the basic idea of a lambda - statement and expression lambdas. It makes sense to start off looking at statement lambdas because these are simply a more concise way of writing an anonymous method.

The basic syntax is:

(comma separated parameters)=>
        {semicolon terminated statement list;}

The => symbol can be read as “becomes” to indicate that the parameters are transformed into the actions.

A lambda expression shares all its characteristics with anonymous methods.

For example, to define the Hello anonymous method listed earlier using a lambda expression you would write something like:

delegate int HelloType(int param);
HelloType HelloInst = (int param1) =>
{
 MessageBox.Show("Hello delegate World"                                        +param1.ToString());
 return ++param1;
};

The idea is that you are still creating an anonymous method but the body of the method is now defined using a slightly different syntax. Once the lambda expression is encapsulated by the delegate instance everything works in the same way. Note there is nothing special about the name param1 - you can call parameters whatever you want. 

There are some tricks that you can use with lambda expressions to make the method definition even more concise and flexible.

The first is that the compiler can deduce the type of the parameters from the delegate type.

Essentially the lambda expression has to have the same number of parameters as the delegate and the return type, if any, has to be implicitly convertible to the return type of the delegate.

Thus the previous lambda expression can be written:

HelloType HelloInst = (param1) =>
{
 MessageBox.Show("Hello delegate World"
                        + param1.ToString());
 return ++param1;
};

You can also leave out the brackets if the lambda has only one parameter

HelloType HelloInst = param1 =>
{
 MessageBox.Show("Hello delegate World"
                        + param1.ToString());
 return ++param1;
};

 

and you can use empty brackets () if there are no parameters at all.

HelloType HelloInst =  () =>
{
 MessageBox.Show("Hello delegate World");
 return 0;
};

You can use a lambda anywhere you would use an anonymous method and they are most often used as parameters as an easy way to pass a function to a method. 



Last Updated ( Thursday, 22 September 2016 )