Lambda and lambda expressions
Lambda
Lambda expressions are anonymous functions that can be used to create a delegate or expression directory tree. By using a lambda expression, you can use it as a parameter or as a local function returned by the function call value. Lambda expressions are particularly useful for writing a LINQ query expression.
To create a Lambda expression, specify the input parameter on the left side of the Lambda operator => (if any), and then enter the expression or statement block on the other side. For example, lambda expressionsx => x * xNamexAnd returnx. As shown in the following example, you can assign this expression to the delegate type:
delegate int MyDel(int i); static void Main(string[] args) { MyDel myDelegate = x => x * x; int j = myDelegate(5); //j = 25 }
Create Expression Tree:
using System.Linq.Expressions; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { Expression<MyDel> myDel = x => x * x; } } }
=>The operator has (=) Same priority and right join operation.
Lambda is used as a parameter for standard query operators (such as Where <TSource>) in method-based LINQ queries.
When you use the method-based syntax to call the Enumerable method in the Where <TSource> class (for example, in the same way as in LINQ to Objects and LINQ to XML), the parameter is the delegate type System. func <T, effectresult>. Using Lambda expressions to create a delegate is the most convenient. For example. linq. when the same method is called in the Queryable class (for example, in LINQ to SQL), the parameter type is System. linq. expressions. expression <Func>, in which Func is any Func delegate with a maximum of 16 input parameters. Similarly, Lambda expressions are just a simple way to construct the Expression Tree.
In the previous example, note that the delegate signature hasintType of implicit type input parameter, and returnint. You can convert a Lambda expression to a delegate of this type because the expression also has an input parameter (x), And a compiler can be implicitly convertedintType. (Type inference will be discussed in detail in the following sections .) When you call a delegate using input parameter 5, it returns Result 25.
Lambda is not allowed on the left side of the is or as operator.
Expression lambda
The lambda expression at the right of the => operator is called "lambda expression ". Lambda is widely used to construct expression trees. Lambda returns the result of the expression in the following basic form:
(input parms) => expression
When lambda has only one input parameter, parentheses are optional; otherwise, parentheses are required. Two or more input parameters in parentheses are separated by commas:
(x, y) => x == y
Sometimes, the compiler is difficult or unable to infer the input type. In this case, you can explicitly specify the type as shown in the following example:
(int x, string s) => s.Length > x
Use parentheses to specify zero input parameters:
() => SomeMethod()
In the previous example, note that the body of the expression Lambda can contain a method call. In addition to the context of the. NET public language runtime, The method does not make any sense.
The lambda statement is similar to the lambda expression, but the statement is enclosed in braces:
(input parms) => {statement;}
The body of a lambda statement can contain any number of statements. However, there are usually no more than two or three statements.
delegate void MyDel(string s); // ...MyDel myDel = n => { string s = n + " " + "World"; Console.WriteLine(s); }; myDel("Hello");
Asynchronous lambda
By Using async and await keywords, you can easily create lambda expressions and statements that contain asynchronous processing. For example, the following Windows form example contains a call and wait Asynchronous MethodExampleMethodAsyncEvent Handler.
public partial class Form1 : Form { public Form1() { InitializeComponent(); } private async void button1_Click(object sender, EventArgs e) { await ExampleMethodAsync(); textBox1.Text += "\r\nControl returned to Click event handler.\r\n"; } async Task ExampleMethodAsync() { await Task.Delay(1000); } }
You can use Asynchronous lambda to add the same event handler. AddasyncModifier,
public partial class Form1 : Form { public Form1() { InitializeComponent(); button1.Click += async (sender, e) => { await ExampleMethodAsync(); textBox1.Text += "\r\nControl returned to Click event handler.\r\n"; }; } async Task ExampleMethodAsync() { await Task.Delay(1000); } }
Lambda with standard query Operators
Many standard query operators have input parameters, which are of the generic delegate generation Func <T, effectresult>. These Delegates use type parameters to define the number and type of input parameters and the return type of the delegate.FuncDelegation is useful for encapsulating User-Defined expressions that are applied to each element in a group of source data. For example, consider the following Delegate types:
public delegate TResult Func<TArg0, TResult>(TArg0 arg0)
The delegate can be instantiatedFunc<int,bool> myFunc, WhereintIs input parameter,boolIs the return value. The return value is always specified in the last type parameter.Func<int, string, bool>The definition contains two input parameters (intAndstring) And the return type isbool. When the followingFuncDuring delegation, the delegate returns true or false to indicate whether the input parameter is equal to 5:
Func<int, bool> myFunc = x => x == 5; bool result = myFunc(4);
When the parameter type isExpression<Func>You can also provide Lambda expressions, such as the standard query operators defined in System. Linq. Queryable. If you specifyExpression<Func>Parameter, lambda will compile as Expression Tree.
A standard query operator, Count <TSource>, is displayed here:
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 explicitly specify this type. This special lambda expression calculates the number of integers whose remainder is 1 (n).
The following code will generate a sequence containingnumbersAll elements on the left of 9 in the array, because it is the first number in the sequence that does not meet the conditions:
var firstNumbersLessThan6 = numbers.TakeWhile(n => n < 6);
This example shows how to specify multiple input parameters by including the input parameters in parentheses. This method returns all elements in the number array until a number with a value smaller than its position is encountered. Do not set the lambda operator (=>) And operators greater than or equal (>=.
var firstSmallNumbers = numbers.TakeWhile((n, index) => n >= index);
Type inference in Lambda
When writing lambda, you do not need to specify a type for the input parameter, because the compiler can infer the type based on the lambda subject, the delegate type of the parameter, 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. Therefore, if you want to queryIEnumerable<Customer>, The input variable is inferredCustomerObject, which means you can access its method and attributes:
customers.Where(c => c.City == "London");
Lambda features:
Lambda must contain the same number of parameters as the delegate type.
Each input parameter in Lambda must be implicitly converted to its corresponding delegate parameter.
The return value (if any) of Lambda must be implicitly converted to the return type of the delegate.
Note that the lambda expression itself does not have a type, because the conventional type system does not have the internal concept of "Lambda expression. However, it is convenient to talk about the "type" of lambda expressions in an informal way. In these cases, the type refers to the Expression type converted to the delegate type or lambda Expression.
Variable range in Lambda expressions
Lambda can referenceExternal variables. Variables captured in this way will be stored for use in lambda expressions, even in other cases, these variables will be out of range and garbage collection. An external variable must be explicitly allocated before it can be used in a lambda expression.
Delegate bool D (); delegate bool D2 (int I); class Test {D del; D2 del2; public void TestMethod (int input) {int j = 0;
// Initialize the delegate del = () => {j = 10; return j> input ;}; del2 = (x) with lambda expressions) ==>{ return x = j ;}; Console. writeLine ("j = {0}", j); bool boolResult = del (); Console. writeLine ("j = {0 }. B = {1} ", j, boolResult);} static void Main () {Test test = new Test (); test. testMethod (5); bool result = test. del2 (10); // output: true Console. writeLine (result); Console. readKey ();}}
The following rules apply to variable ranges in lambda expressions:
The captured variables will not be recycled as garbage until the delegate that references the variables meets the garbage collection conditions.
Variables introduced in lambda expressions cannot be seen in external methods.
Lambda expressions cannot be directly captured from the closed MethodrefOroutParameters.
The Return Statement in the Lambda expression does not cause the return of the closed method.
If the target of the jump statement is outside the block, the lambda expression cannot containgotoStatement,breakStatement orcontinueStatement. Similarly, if the target is inside the block, it is also incorrect to use the jump statement outside the lambda function block.