Monday 10 September 2012

Lambda Expressions

A Lambda expression is an Anonymous function, that is more concise and flexible. You can use lambda expression to create inline delegates or expression tree type(s).

By using lambda expressions, you can write local functions that can be passed as arguments or returned as the value of function calls. Lambda expressions are particularly helpful for writing LINQ query expressions.

Although both anonymous methods and lambda expressions allow you define the method implementation inline, but they do slightly differ on how they are implemented. An anonymous method explicitly requires you to define the parameter types and the return type for a method, where as lambda expression uses the type inference feature which allows the compiler to infer the type of the variable based on the context.

A typical lambda expression looks like:

           Input Parameter => Expression or Statement block

The symbol => is known as lambda operator. On the left hand side of lambda operator you specify input parameters (if any) and you put the expression or statement block on the other side.

A simplest example of lambda expression:

           x => x * x
        
The lambda expression above, specifies a parameter that’s named x and returns the value of x squared.

Operator Lambda:

The symbol => is known as lambda operator, which is read as “goes to”.  The => operator has the same precedence as assignment (=) and is right-associative.

The term right-associative means when two or more operators that have the same precedence are present in an expression, they are evaluated in order from right to left.

Expression Lambda:

A lambda expression with an expression on the right side is called an expression lambda.An expression lambda returns the result of the expression and takes the following basic form:

           (Input Parameters) => Expression

The parentheses are optional if the lambda has one input parameter:

           x => x + 1

Two or more input parameters are separated by commas and enclosed in parentheses:

           (x, y) => x == y

Sometimes it is difficult for the compiler to infer the input types. In that case, you can specify the types explicitly:

           (int x, string s) => s.Length > x

Specify zero input parameters with empty parentheses:

           () => SomeMethod();

           () => new Orders(7));

Statement Lambda:

A statement lambda resembles an expression lambda except that the statement(s) is enclosed in braces followed by a semicolon(;):

           (Input Parameters) => {Statement;};

The body of a statement lambda can consist of any number of statements:

           (int x) => { if (x==1)  return x;  else return  x * x;  };

Lambdas with Inline Delegates:

Earlier we used to create inline delegates with the help of Anonymous methods only, like:


Nowdays we can create inline delegates using Lambda expressions, that is the most convenient way to create inline delegates.


In the example, notice that the delegate signature has one implicitly-typed input parameter of type int, and returns an int. The lambda expression can be converted to a delegate of that type because it also has one input parameter (x) and a return value that the compiler can implicitly convert to type int. When the delegate is invoked by using an input parameter of 5, it returns a result of 25.

Lambdas with Generic Delegates:

Func<>, Action<> and Expression<> are the new generic delgates introduced by Microsoft. Many Standard query operators have an input parameter whose type is one of the Func<T, TResult> family of generic delegates.

The Func<> delegates are very useful for encapsulating user-defined expressions that are applied to each element in a set of source data.


In the example, the Func<int, bool> delegate, when it is invoked, will return true or false to indicate whether the input parameter is odd or even number. Like:

           Func<int, bool> myFunc = n => n % 2 == 1;
           bool result = myFunc(4); // returns false
The Func delegate is instantiated as Func<int,bool> myFunc where int is an input parameter and bool is the return value. The return value is always specified in the last type parameter.

Type Inference in Lambdas:

When writing lambdas, you often do not have to specify a type for the input parameters because the compiler can infer the type based on the lambda body, the underlying delegate type, and other factors as described in the C# Language Specification.

For most of the standard query operators, the first input is the type of the elements in the source sequence. So if you are querying an IEnumerable<Customer>, then the input variable is inferred to be a Customer object, which means you have access to its methods and properties:

           customers.Where(c => c.City == "London");

The general rules for lambdas are as follows:
  • The lambda must contain the same number of parameters as the delegate type.
  • Each input parameter in the lambda must be implicitly convertible to its corresponding delegate parameter.
  • The return value of the lambda (if any) must be implicitly convertible to the delegate's return type.

Variable Scope in Lambdas:

Lambdas can refer to outer variables that is in the scope of the method or type in which the lambda is defined.

The following rules apply to variable scope in lambda expressions:
  • A variable that is captured will not be garbage-collected until the delegate that references it goes out of scope.
  • Variables introduced within a lambda expression are not visible in the outer method.
  • A lambda expression cannot directly capture a ref or out parameter from an enclosing method.
  • A return statement in a lambda expression does not cause the enclosing method to return.
  • A lambda expression cannot contain a goto statement, break statement, or continue statement whose target is outside the body or in the body of a contained anonymous function.
  • An outer variable must be definitely assigned before it can be consumed in a lambda expression. The following example demonstrates these rules.

How to use Lembdas in LINQ:

Lambda expressions are not directly used in queries syntax. They are used in query based method like Where or FindAll. But query expressions can contain lembda enabled method calls.

Example 1: The following example demonstrates how to use a lambda expression in a method-based query by using the Enumerable.Where standard query operator. Note that the Where method in this example has an input parameter of the delegate type Func<TResult> and that delegate takes an integer as input and returns a Boolean. The lambda expression can be converted to that delegate.


Example 2: The following example demonstrates how to use a lambda expression in a method call of a query expression. The lambda is necessary because the Sum() standard query operator cannot be invoked by using query syntax.



How to use Lembdas outside LINQ:

Lambda expressions are not limited to LINQ queries. You can use them anywhere a delegate value is expected, that is, wherever an anonymous method can be used.

Example: The following example shows how to use a lambda expression in a Windows Forms event handler. Notice that the types of the inputs (Object and MouseEventArgs) are inferred by the compiler and do not have to be explicitly given in the lambda input parameters.



Framework:

.Net 3.0, 3.5, 4.0, 4.5

References:

No comments:

Post a Comment