How to use Lambda expressions (C #) quickly,
Lambda expressions are an anonymous function that can be used to create delegate or expression tree types. By using lambda expressions, you can write a local function that can be passed as a parameter or returned as a function call value. Lambda expressions are particularly useful for writing LINQ query expressions.
To create a Lambda expression, you need to specify input parameters (if any) on the left side of the Lambda operator => and then enter the expression or statement block on the other side. For example, the lambda expression x => x * x specifies a parameter named x and returns the squared value of x. As the following example shows, you can assign this expression to a delegate type:
C # copy
delegate int del (int i);
static void Main (string [] args)
{
del myDelegate = x => x * x;
int j = myDelegate (5); // j = 25
}
To create an expression tree type:
C # copy
using System.Linq.Expressions;
namespace ConsoleApplication1
{
class Program
{
static void Main (string [] args)
{
Expression <del> myET = x => x * x;
}
}
}
The => operator has the same precedence as the assignment operator (=) and is a right join operation (see the "Combination" section of the "Operators" article).
Lambda is used as a parameter for standard query operator methods such as <xref: System.Linq.Enumerable.Where% 2A> in method-based LINQ queries.
When calling the <xref: System.Linq.Enumerable> method in the <xref: System.Linq.Enumerable.Where% 2A> class using method-based syntax (as in LINQ to Objects and LINQ to XML), the parameter is a delegate Type <xref: System.Func% 602? DisplayProperty = fullName>. It is most convenient to create this delegate using a Lambda expression. For example, when calling the same method in the <xref: System.Linq.Queryable? DisplayProperty = fullName> class (as in LINQ to SQL), the parameter type is <xref: System.Linq.Expressions.Expression? DisplayProperty = fullName > <func \>, where Func is any Func delegate with up to sixteen input parameters. Similarly, a Lambda expression is just a very concise way to structure the expression tree. Despite the fact that objects created with Lambda have different types, Lambda makes Where calls look similar.
In the previous example, notice that the delegate signature has an implicit type input parameter of type int and returns int. You can convert a Lambda expression to a delegate of that type because the expression also has an input parameter (x) and a compiler implicit conversion to a return value of type int. (Type inference is discussed in detail in the following sections.) When the delegate is called with input parameter 5 it returns result 25.
Lambda is not allowed to the left of the is or as operator.
All restrictions that apply to anonymous methods also apply to Lambda expressions. For more information, see Anonymous Methods.
Expression lambda
Lambda expressions with expressions to the right of the => operator are called "expression lambdas." Expression lambdas are widely used in the construction of expression trees. The expression lambda returns the result of the expression and takes the following basic form:
C # copy
(input-parameters) => expression
Parentheses are optional only if the lambda has only one input parameter; otherwise, parentheses are required. Two or more input parameters in parentheses are separated by commas:
C # copy
(x, y) => x == y
Sometimes it is difficult or impossible for the compiler to infer the input type. If this happens, you can explicitly specify the type as shown in the following example:
C # copy
(int x, string s) => s.Length> x
Use zero parentheses to specify zero input parameters:
C # copy
() => SomeMethod ()
In the previous example, notice that the body of the expression Lambda can contain a method call. However, if you are creating an expression directory tree that is evaluated outside the .NET Framework (for example, in SQL Server), you should not use method calls in lambda expressions. Outside of the .NET common language runtime context, methods will not make any sense.
Statement lambda
The statement lambda is similar to the expression lambda expression, except that the statement is enclosed in curly braces:
(input-parameters) => {statement;}
The body of a statement lambda can contain any number of statements; however, it is usually not more than two or three.
C # copy
delegate void TestDelegate (string s);
C # copy
TestDelegate del = n => {string s = n + "World";
Console.WriteLine (s);};
Like anonymous methods, statement lambdas cannot be used to create expression trees.
Asynchronous lambda
By using the async and await keywords, you can easily create lambda expressions and statements that include asynchronous processing. For example, the following Windows Forms example contains an event handler that calls and waits on the asynchronous method ExampleMethodAsync.
C # copy
public partial class Form1: Form
{
public Form1 ()
{
InitializeComponent ();
}
private async void button1_Click (object sender, EventArgs e)
{
// ExampleMethodAsync returns a Task.
await ExampleMethodAsync ();
textBox1.Text + = "\ r \ nControl returned to Click event handler. \ n";
}
async Task ExampleMethodAsync ()
{
// The following line simulates a task-returning asynchronous process.
await Task.Delay (1000);
}
}
You can add the same event handler using an asynchronous lambda. To add this handler, add an async modifier before the lambda parameter list, as shown in the following example.
C # copy
public partial class Form1: Form
{
public Form1 ()
{
InitializeComponent ();
button1.Click + = async (sender, e) =>
{
// ExampleMethodAsync returns a Task.
await ExampleMethodAsync ();
textBox1.Text + = "\ nControl returned to Click event handler. \ n";
};
}
async Task ExampleMethodAsync ()
{
// The following line simulates a task-returning asynchronous process.
await Task.Delay (1000);
}
}
For more information on how to create and use asynchronous methods, see Asynchronous Programming with Async and Await.
Lambda with standard query operators
Many standard query operators have input parameters whose type is one of the generic delegate family <xref: System.Func% 602>. These delegates use type parameters to define the number and type of input parameters and the return type of the delegate. Func delegates are useful for encapsulating user-defined expressions that are applied to each element in a set of source data. For example, consider the following delegate types:
C # copy
public delegate TResult Func <TArg0, TResult> (TArg0 arg0)
You can instantiate a delegate 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. Func <int, string, bool> Defines a delegate with two input parameters (int and string) and a return type of bool. When the following Func delegate is called, the delegate returns true or false to indicate whether the input parameter is equal to 5:
C # copy
Func <int, bool> myFunc = x => x == 5;
bool result = myFunc (4); // returns false of course
When the parameter type is Expression <Func>, you can also provide Lambda expressions, such as in the standard query operators defined in System.Linq.Queryable. If you specify the Expression <Func> parameter, the lambda is compiled into an expression directory tree.
A standard query operator is shown here, the <xref: System.Linq.Enumerable.Count% 2A> method:
C # copy
int [] numbers = {5, 4, 1, 3, 9, 8, 6, 7, 2, 0};
int oddNumbers = numbers.Count (n => n% 2 == 1);
The compiler can infer the type of the input parameter, or you can specify the type explicitly. This special lambda expression will count the number (n) of those integers with a remainder of 1 when divided by 2.
The following line of code will generate a sequence containing all the elements in the numbers array to the left of 9 because it is the first number in the sequence that does not meet the criteria:
C # copy
var firstNumbersLessThan6 = numbers.TakeWhile (n => n <6);
This example shows how to specify multiple input parameters by enclosing them. This method returns all elements in the array of numbers until it encounters a number with a value less than its position. Do not confuse the lambda operator (=>) with the greater than or equal to operator (> =).
C # copy
var firstSmallNumbers = numbers.TakeWhile ((n, index) => n> = index);
Type inference in Lambda
When writing a lambda, you usually don't have to specify the type for the input parameters because the compiler can infer the type based on the lambda body, the delegate type of the parameters, and other factors described in the C # language specification. For most standard query operators, the first input is the element type in the source sequence. So if you are querying IEnumerable <Customer>, the input variable will be inferred as a Customer object, which means you can access its methods and properties:
C # copy
customers.Where (c => c.City == "London");
Lambda's general rules are as follows:
Lambda must contain the same number of parameters as the delegate type.
Every input parameter in Lambda must be able to be implicitly converted to its corresponding delegate parameter.
Lambda's return value, if any, must be able to be implicitly converted to the return type of the delegate.
Note that the lambda expression itself has no type, because the general type system has no internal concept of "Lambda expression". However, sometimes it is convenient to talk about the "type" of a lambda expression in an informal way. In these cases, the type is the <xref: System.Linq.Expressions.Expression> type to which the delegate type or lambda expression is converted.
Variable scope in Lambda expressions
Within a method that defines a lambda function or a type that contains a Lambda expression, Lambda can reference external variables in scope (see Anonymous Methods). Variables captured in this way are stored for use in lambda expressions, even though in other cases these variables will be out of scope and garbage collected. An external variable must be explicitly assigned before it can be used in a lambda expression. The following example demonstrates these rules:
C # copy
delegate bool D ();
delegate bool D2 (int i);
class Test
{
D del;
D2 del2;
public void TestMethod (int input)
{
int j = 0;
// Initialize the delegates with lambda expressions.
// Note access to 2 outer variables.
// del will be invoked within this method.
del = () => {j = 10; return j> input;};
// del2 will be invoked after TestMethod goes out of scope.
del2 = (x) => {return x == j;};
// Demonstrate value of j:
// Output: j = 0
// The delegate has not been invoked yet.
Console.WriteLine ("j = {0}", j); // Invoke the delegate.
bool boolResult = del ();
// Output: j = 10 b = True
Console.WriteLine ("j = {0}. B = {1}", j, boolResult);
}
static void Main ()
{
Test test = new Test ();
test.TestMethod (5);
// Prove that del2 still has a copy of
// local variable j from TestMethod.
bool result = test.del2 (10);
// Output: True
Console.WriteLine (result);
Console.ReadKey ();
}
}
The following rules apply to variable ranges in lambda expressions:
Captured variables will not be garbage collected until the delegate that references the variable is eligible for garbage collection.
Variables introduced inside lambda expressions are not visible in external methods.
Lambda expressions cannot capture ref or out parameters directly from closed methods.
A return statement in a lambda expression does not cause a closed method to return.
If the target of a jump statement is outside a block, the lambda expression cannot contain