Saturday, January 30, 2010

Lambda Expressions

C# 2.0 introduces anonymous methods, which allow code blocks to be written "in-line" where delegate values are expected. While anonymous methods provide much of the expressive power of functional programming languages, the anonymous method syntax is rather verbose and imperative in nature. Lambda expressions provide a more concise, functional syntax for writing anonymous methods.
A lambda expression is written as a parameter list, followed by the => token, followed by an expression or a statement block.
expression:
assignment
non-assignment-expression
non-assignment-expression:
conditional-expression
lambda-expression
query-expression
lambda-expression:
(   lambda-parameter-listopt   )   =>   lambda-expression-body
implicitly-typed-lambda-parameter   =>   lambda-expression-body
lambda-parameter-list:
explicitly-typed-lambda-parameter-list
implicitly-typed-lambda-parameter-list
explicitly-typed-lambda-parameter-list
explicitly-typed-lambda-parameter
explicitly-typed-lambda-parameter-list   ,   explicitly-typed-lambda-parameter
explicitly-typed-lambda-parameter:
parameter-modifieropt   type   identifier
implicitly-typed-lambda-parameter-list
implicitly-typed-lambda-parameter
implicitly-typed-lambda-parameter-list   ,   implicitly-typed-lambda-parameter
implicitly-typed-lambda-parameter:
identifier
lambda-expression-body:
expression
block
The parameters of a lambda expression can be explicitly or implicitly typed. In an explicitly typed parameter list, the type of each parameter is explicitly stated. In an implicitly typed parameter list, the types of the parameters are inferred from the context in which the lambda expression occurs-specifically, when the lambda expression is converted to a compatible delegate type, that delegate type provides the parameter types (§26.3.1).
In a lambda expression with a single, implicitly typed parameter, the parentheses may be omitted from the parameter list. In other words, a lambda expression of the form
( param ) => expr
can be abbreviated to
param => expr
Some examples of lambda expressions follow below:
x => x + 1                     // Implicitly typed, expression body
x => { return x + 1; }         // Implicitly typed, statement body
(int x) => x + 1               // Explicitly typed, expression body
(int x) => { return x + 1; }   // Explicitly typed, statement body
(x, y) => x * y               // Multiple parameters
() => Console.WriteLine()      // No parameters
In general, the specification of anonymous methods, provided in §21 of the C# 2.0 Specification, also applies to lambda expressions. Lambda expressions are a functional superset of anonymous methods, providing the following additional functionality:
  • Lambda expressions permit parameter types to be omitted and inferred whereas anonymous methods require parameter types to be explicitly stated.
  • The body of a lambda expression can be an expression or a statement block whereas the body of an anonymous method can only be a statement block.
  • Lambda expressions passed as arguments participate in type argument inference (§26.3.2) and in method overload resolution (§26.3.3).
  • Lambda expressions with an expression body can be converted to expression trees (§26.8).
    Note   The PDC 2005 Technology Preview compiler does not support lambda expressions with a statement block body. In cases where a statement block body is needed, the C# 2.0 anonymous method syntax must be used.

Lambda Expression Conversions

Similar to an anonymous-method-expression, a lambda-expression is classified as a value with special conversion rules. The value does not have a type but can be implicitly converted to a compatible delegate type. Specifically, a delegate type D is compatible with a lambda-expression L provided:
  • D and L have the same number of parameters.
  • If L has an explicitly typed parameter list, each parameter in D has the same type and modifiers as the corresponding parameter in L.
  • If L has an implicitly typed parameter list, D has no ref or out parameters.
  • If D has a void return type and the body of L is an expression, when each parameter of L is given the type of the corresponding parameter in D, the body of L is a valid expression that would be permitted as a statement-expression (§8.6).
  • If D has a void return type and the body of L is a statement block, when each parameter of L is given the type of the corresponding parameter in D, the body of L is a valid statement block in which no return statement specifies an expression.
  • If D has a non-void return type and the body of L is an expression, when each parameter of L is given the type of the corresponding parameter in D, the body of L is a valid expression that is implicitly convertible to the return type of D.
  • If D has a non-void return type and the body of L is a statement block, when each parameter of L is given the type of the corresponding parameter in D, the body of L is a valid statement block with a non-reachable end point in which each return statement specifies an expression that is implicitly convertible to the return type of D.
The examples that follow use a generic delegate type Func which represents a function taking an argument of type A and returning a value of type R:
delegate R Func(A arg);
In the assignments
Func f1 = x => x + 1;         // Ok
Func f2 = x => x + 1;      // Ok
Func f3 = x => x + 1;      // Error
the parameter and return types of each lambda expression are determined from the type of the variable to which the lambda expression is assigned. The first assignment successfully converts the lambda expression to the delegate type Func because, when x is given type int, x + 1 is a valid expression that is implicitly convertible to type int. Likewise, the second assignment successfully converts the lambda expression to the delegate type Func because the result of x + 1 (of type int) is implicitly convertible to type double. However, the third assignment is a compile-time error because, when x is given type double, the result of x + 1 (of type double) is not implicitly convertible to type int.

No comments:

Post a Comment