About Me

Hyderabad, Andhra Pradesh, India

Wednesday, June 29, 2011

Lambda Expressions

Linq is always associated with Lambda Expressions. In .NET 2.0 we have the concept of Anonymous Methods that allows you to write function body inline without the need of writing a delegate function. Lambda Expression of .NET 3.5 is too concise the concept of Anonymous function writing.
Let us take a look of how to write Anonymous methods in C# 2.0.

int i = this.compute(10);

private int compute(int value)

{

return (value + 2);

}

It is very normal example of a function call. The compute function is called when the line i=this.compute(10) is called. We can replace the above code with inline anonymous function like this:

//C#

delegate int DelType(int i);

DelType dd = delegate(int value)

{

return (value +2);

};

int i = dd(10);

In the 2nd Case we can see that just declaring a Delegate and giving instance of that delegate type we can easily manage to write anonymous methods. .NET 3.5 puts forward this concept a little more compact. We can take the use of => operator which is introduced in .NET 3.5. It gives more flexible and easier way to write expression. Lambda Expressions can be used in the previous case to get the result like this:

delegate int DelType(int i);

DelType d = value => value + 2;

int i = d(10);

Thus the delegate type is assigned directly. The meaning of the line value =>value + 2 is just similar to declaring a function. The first value indicates the arguments that we pass in a function and the one after the "=>" operator is the body of the function. Similarly if we want we can feed in as many arguments as we want to. Just in the following examples:

// Method with 2 arguments

delegate int DelType(int i, int j);

DelType d = (value1,value2) => value1 + value2;

int i = d(10,20) // Returns 30

In this example we passed in 2 arguments to the function and returns the result. You may also wonder how I can write a lambda expression when your function body takes more than one expression. Don’t worry, it’s simple. Take a look at the following example.

// Multiline Function Body

delegate int DelType(int i, int j);

DelType d = (value1,value2) => {

value1 = value1 + 2;

value2 = value2 + 2;

return value1 + value2;

};

Thus we see writing Lambda expression is very easy. This comes very handy when working with linq, as most of the extension methods that are associated with Linq takes function delegates as arguments. We can pass simple delegate function body easily to those functions to perform work easily.

Generic Lambda Expression

However, whenever a lambda expression is required, we need to define a delegate type for this. This is very awkward and less productive. .NET 3.5 introduces generic delegate which simplifies the lambda expression much better and simpler. It provides two pre-defined generic delegates Func and Action. Using these delegates, you do not need to explicitly define a delegate. The difference between Func and Action is the return type. Func supports return type however Action supports methods with void return type. These delegates provide a set of pre-defined signatures that are ready to use.

// Pre-defined Func delegates
delegate TResult Func();
delegate TResult Func(T1 arg1);
delegate TResult Func(T1 arg1, T2 arg2);
delegate TResult Func(T1 arg1, T2 arg2, T3 arg3);
delegate TResult FuncT1 arg1, T2 arg2, T3 arg3, T4 arg4);

// Pre-defined Action delegates
delegate void Action(T1 arg1);
delegate void Action(T1 arg1, T2 arg2);
delegate void ActionT1 arg1, T2 arg2, T3 arg3);
delegate void ActionT1 arg1, T2 arg2, T3 arg3, T4 arg4);

As mentioned above Func and Action provide very lighter syntax which avoids the need to declare a Delegate type for a lambda expression. Code 1 shows the usage of Func.

// Code 1

// Generic Lambda Expression Usage

Func Square = x => x * x;

int result = Square(4);

Console.WriteLine(result); // 16

Delegate type declaration is not necessary when using generic lambda expression. In Code 1, you can see that Func Square provides parameterized type for the expression x => x * x;. This enables the C# compiler to infer the type detail of x. Note that delegate type declaration also provides type details to C# compiler, however this syntax improves developer productivity. This satisfies factor #3 Parameterized types. Let us see one more example (Code 2) using generic lambda expression which satisfies next two functional factors.

// Code 2

// Generic Lambda Expression Usage

List primes = new List();

List primeCubes = new List();

// adding set of values to primes

primes.Add(2); primes.Add(3); primes.Add(5); primes.Add(7);

// iterate through primes elements and calculate cube and

// add it to primeCubes using Action action

primes.ForEach(x => primeCubes.Add(x * x * x));

foreach (int i in primeCubes)

{

Console.WriteLine(i);

}

ForEach in .NET 3.5 generic collections requires Action type, here Action. The line primes.ForEach(x => primeCubes.Add(x * x * x)); shows how C# 3.0 allows you to easily pass a method as an argument to a method. Here x => primeCubes.Add(x * x * x) function is passed as argument. This proves that C# 3.0 satisfies functional factor #4 high order function. In this example, you can also see the immutability nature of .NET 2.0's collection types so that I have used one more List type primeCubes.


No comments:

Post a Comment