Document directory
- Lambda expressions
- 1. Use the naming method
- 2. Use the anonymous method
- 3. Use lambda expressions
- Summary
- Content source
C #3.0 new features-lambda expressions
Lambda expressions
In C #3.0, Microsoft added the "Lambda expression ". Lamdba expressions were originally used in a long time ago lisp computer language. In 1936, an American mathematician Alonzo Church gave a conceptual description of the lamdba expressions. These expressions provide convenient syntax to specify an algorithm.
But before introducing lambda expressions, Let's first look at the evolution process of parameters that specify an algorithm as a method, because this is exactly the purpose of lambda expressions.
1. Use the naming method
Before C #2.0, when a method or variable needs to use a delegate, the developer must create a naming method and input the name at the place where the delegate is required. For example, consider the following situations.
Suppose there are two developers, one is a general-purpose code developer, and the other is an application developer. However, there is no need for two developers to describe two different roles by TAG. Common Code developers need to create common target code, which can be reused throughout the project. Application developers will use these code for general purposes to create an application.
In this example, the general code developer wants to create a general method to filter the integer array, but this general method must be able to specify the algorithm used to filter the array. First, the developer must declare a delegate. The design prototype of the delegate is to receive an int type. If the filtered array does contain an int type, the delegate returns true.
Therefore, the developer creates a tool class and adds delegate and filtering methods. The announcement code is as follows:
| 1234567891011121314151617 |
public class Common { public delegate bool IntFilter(int i); public static int[] FilterArrayOfInts(int[] ints, IntFilter filter) { ArrayList aList = new ArrayList(); foreach (int i in ints) { if (filter(i)) { aList.Add(i); } } return ((int[])aList.ToArray(typeof(int))); } } |
Developers of this public code will put the delegate statement and the filterarrayofints method into a public library, that is, a dynamic link library (DLL, in this way, you can use this annotation and method in multiple applications.
The filterarrayofints method listed above allows application developers to pass an integer array and a delegate as parameters to the filtering method and obtain a filtered array.
Now, it is assumed that the application developer only wants to filter odd numbers. You can refer to the following filtering method, which is declared in the developer's application code.
| 1234567 |
public class Application { public static bool IsOdd(int i) { return ((i & 1) == 1); } } |
According to the Code in the filterarrayofints method, each int integer in the input array will call this method. If the number of int integers transmitted is an odd number, only true is returned for this filtering method. The following is an example:
| 1234567 |
int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; int[] oddNums = Common.FilterArrayOfInts(nums, Application.IsOdd); foreach (int i in oddNums) { Console.WriteLine(i); } |
The running result of the example is as follows:
Note that to pass delegate as the second parameter of the filterarrayofints method, the application developer only needs to pass the name of the method. You only need to create another filter. application developers can filter different data. Application developers can also create filters for even numbers, prime numbers, and any desired rules. Method delegation can be used to become highly reusable code.
2. Use the anonymous method
The methods described above are very useful and good, but it is tedious to delegate code for all these filtering methods and any other required methods. In fact, many methods are only used for a single call. Therefore, it is very troublesome to create a naming method for all these methods. Starting from C #2.0, developers can use anonymous methods to pass Inline code, that is, replacing method delegation with Inline code. The anonymous method allows developers to specify a piece of filtering code at the location where the method delegate is usually passed. Example:
| 123456789 |
int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; int[] oddNums = Common.FilterArrayOfInts(nums , delegate(int i) { return ((i & 1) == 1); }); foreach (int i in oddNums) { Console.WriteLine(i); } Console.Read(); |
This is really cool. Application developers no longer need to declare a method anywhere. This method is good for filtering logic code that does not need to be reused in the future. As required by the code, the running result of this example is the same as that of the previous example.
3. Use lambda expressions
Lambda expressions can be written as a comma-separated parameter list followed by a Lambda operator followed by an expression or declaration function. If multiple input parameters exist, parentheses are used to include the input parameters. In C #, the lambda operator can be written as "=> ". In this way, the lambda expression in C # can be written:
| 1 |
(param1, param2, ...paramN) => expr |
When you need more complex expressions, you can use the following function declaration:
| 12345678 |
(param1, param2, ...paramN) => { statement1; statement2; ... statementN; return(lambda_expression_return_type); } |
In this example, this function declares that the last data type to be put back must match the data type specified by Delegate.
The following is a simple example of a Lambda expression:
This Lambda expression can be read as "X to X", or read as "input x returns X ". This means that the input variable X will return X. This expression is only used to return input parameters. Because this expression only uses one input parameter X, it does not need to be included in parentheses. It is very important to know that delegate indicates the type of the input parameter X and the type of the value to be returned. For example, if delegate is defined as a string-type parameter and a bool value is returned, the X => X expression cannot be used, this is because if the input parameter X is of the string type, the returned value should also be of the string type. However, delegate specifies that the return value must be of the bool type. Therefore, for delegate defined as such, the part on the right of the lambda operator (=>) in the expression must be equal to or return a bool value, for example:
This Lambda expression can be read as "X to X. length> 0", or "input x returns X. length> 0 ". Because the right part of this expression is equal to a bool value, delegate should specify that this method will return a bool value, otherwise it will be compiled incorrectly.
The following Lambda expression returns the length of the input parameter. Therefore, delegate should specify an int type return value:
To pass multiple parameters into a Lambda expression, you can use commas to separate these parameters and include them in parentheses. For example:
Complex lambda expressions even use function declarations, such:
| 1234567 |
(x, y) => { if (x > y) return x; else return y; } |
The important thing to remember is that delegate defines the type of input value and the type of value that must be returned. Therefore, make sure that the lambda expression matches the delegate definition.
Warning make sure that the compiled Lambda expression meets the input type specified by the delegate definition and returns the return type defined by the delegate.
For more information, see the delegate Statement defined by the announcement code developer below:
| 1 |
public delegate bool IntFilter(int i); |
The Lambda expression of the application developer must support passing in an int type parameter and return a bool type value. This can be inferred through the method called by the expression and the filtering method function. However, it is important to remember that this is specified by the delegate.
If lambda expressions are used, the above instance can be written as follows:
| 1234567 |
int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; int[] oddNums = Common.FilterArrayOfInts(nums, i => ((i & 1) == 1)); foreach (int i in oddNums) { Console.WriteLine(i); } |
Indeed, the code is really concise. This piece of code looks interesting because it is very new, but once used to writing code like this, you can be sure that the code is readable and maintainable. As expected, the running result of this Code is the same as the running structure of the previous example:
Summary
The following lists the key code lines in the sample code for each method:
| 12345678910 |
int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; // 1. Use the naming methodint[] oddNums = Common.FilterArrayOfInts(nums, Application.IsOdd); // 2. Use the anonymous methodint[] oddNums = Common.FilterArrayOfInts(nums , delegate(int i) { return ((i & 1) == 1); }); // 3. Use a Lambda expressionint[] oddNums = Common.FilterArrayOfInts(nums, i => ((i & 1) == 1)); |
From the code above, we can see that the code line of the first method is shorter, but do not forget that a naming method must be declared in other places of the Code to define the function of this method. Of course, if the filtering logic will be re-used in many locations in the future, or the algorithm of this method is complex and must be trusted by specific developers, creating a naming method that can be used by other developers is more meaningful.
Tip: it is best to use the naming method for complex and reusable algorithms, so that any developer can easily re-use these algorithms, and developers do not have to know the algorithm in detail.
Content source
Pro LINQ language integrated query in C #2008 -- Joseph C. rattz, Jr.