Delegates, Lambda Expressions, Func and Action

These are few keywords which intermediate programmers are afraid of. Mainly because they don’t use them often which do not allow them to discuss it with their peers. I will try to explain them using less technical words (avoiding variance concepts).

Before getting into the details I would like to go through over the following concepts

  • Callback patterns in Javascript
  • Delegates in C#

If you are familiar with Javascript and JQuery (which I believe most of us should be), you must have come across the following lines of code.

document.ready(function(){
alert(“Hello World”);
});

Above code is a simple implementation where it waits for the html document to be ready and the DOM to be loaded in the browser. As soon as the DOM is fully loaded and document is ready to be processed the anonymous function is triggered. This anonymous function is passed as an argument in the ready() function.

This is a smart way to give control to the programmers to let them execute whatever they want on a certain event during the processing. These anonymous functions are context aware i.e., they keep track of attributes/variables which are referred in the function body even if the parent function is completely executed and returned.

Delegates

If we want to achieve the same behavior in C#, we will need to use delegates. Delegates can be used as an argument of a method or a property of a class. A delegate is a pointer to a method that accepts zero or more arguments and may return a value. Following is a small example of using delegate. First we need to define a new delegate which is done by using delegate keyword.

public delegate void Del(string message);

Now we should have a method which satisfies the arguments and return types of the delegates.

Public void Greetings(string message) {
Console.WriteLine(message);
}

We can now assign this method to the delegate.

Del handler = Greetings;

We can execute the method by using delegate handler(); and it will execute the Greetings() method body.

We can achieve the same simplicity of Javascript by using delegate in a methods argument thus providing more control to the methods caller. Methods caller will also provide the arguments i.e., a function to execute. We can execute that function in our implementation at an appropriate event i.e.,

If(user!= null){
Handler();
}

The above scheme works to sort out different programming problems and is necessary for different programming patterns to implement. It also makes your code more flexible and extendable as the behavior can be changed on the discrete of caller without changing your code.

Although the above is good enough to work, but it’s tedious as compared to Javascript anonymous function. Therefore, C# provided Func and Action to avoid all of this code writing as much as possible. (Note: There can be other reasons but currently we are focusing on Func and Action so let’s stick to it.)

There can be two kind of functions which based on return values.

  • One that returns no value
  • Second that returns a value

One that doesn’t not return a value are encapsulated by the Action keyword. Actions only accepts one or more parameters but do not return a value.

Second that does return a value are encapsulated by the Func keyword. Func accepts the method arguments as well as they return a value.

Now that we understand the delegate and we still want to make it more readable and also if we could define a method inline it would be great just like Javascript.

Lambda Expressions

Is an expression which accepts an argument and has a processing expression which can return a value. Following is a lambda expression implementation of the Greetings method we have seen above.

string message = “Hello World”;
Del handler = (message) => Console.WriteLine(message);

We have created an inline method which accepts message as an argument and it writes greetings on console. We have assigned this inline method to a delegate handler.

Since the message is also defined separately, the anonymous method will have its value and keep itself context aware.

If you have more than one lines to execute in a lambda expression, you can use curly brackets to define a body for the method.

Del handler = (message) => {
Console.WriteLine(message);
}

Action<T1,T2>

As explained earlier we do not expect an action to return a value. All the arguments that are being accepted in the generic arguments will be used as input for the method. As Action is just a delegate i.e., pointer to a method, any method that matches the signature can be assigned to the Action.

Action<string> myAction = Greetings;

Considering the above delegate example, Greetings accepted a string value and printed it on the Console. Above action also accepts a string value and it doesn’t return a value so Greetings can be assigned to myAction. Later this myAction can be invoked on its own will based on certain events just like delegates.

We can also use lambda expression to avoid defining a method Greetings.

string message = “Hello World”;
Action<String> myAction = (message) => Console.WriteLine(message);

Action encapsulates number of overloads which can accept up to 16 arguments in a method. As the arguments are based on generics, we can put any type of arguments.

Now consider if we have to deduct an amount from bank and Tax rate keeps on changing. We can use the signatures

public void DeductAccount(int money, Action<int> DeductTax);

Caller will have the responsibility to provide the latest definition to deduct tax. Even if tax calculation is changed in future our code will still remain the same.

Func<T1, T2>

Like Action, Func also encapsulates a delegate but Func must return a value. The basic difference between Func and Action is that Func returns a value and Action doesn’t.

Func accepts arguments in generics as well. All of its arguments are input to the method except the last argument provided. Last argument is always the return variable.

Func also has overloads and can support up to 16 arguments in a method. Following are few examples Func.

Func<int, int> increment = (x) => x + 1;

Above Func is accepting a method/lambda expression which accepts an integer, increment it by 1 and return the resultant value.

If you have multiple lines of code to execute in the lambda expression. You can again write as

Func<int, int> func2 = x => {
return x + 1;
};

Another simple example can be

Func<int, int, int> product = (x, y) => x * y;

Where the Func accepts two integer arguments and return the product of them.

All the delegates and their variants run on the same thread until and unless we invoke them differently and force them to execute asynchronously.

 

3 thoughts on “Delegates, Lambda Expressions, Func and Action

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.