[Original address] New "orcas" Language Feature: lambda expressions
[Original article publication date] Sunday, 2017l 08,200 7 pm
Last month I started a post series to discuss some new VB and C # language features released as part of Visual Studio and. NET Framework orcas. The first two posts in this series are as follows:
- Automatic attributes, object initializing, and set initializing
- Extension Method
Today's post discusses another basic new language feature:Lambda expressions.
What is a Lambda expression?
C #2005, released with vs 2.0, introduced the concept of an anonymous method, which allows "in-line" to be used where the expected proxy (delegate) value is )"CodeBlock (code blocks) for replacement.
Lambda expressions provide more concise functional syntaxes for writing anonymous methods, but the results are extremely useful when writing a LINQ query expression, because they provide a very compact and class-safe method to write functions that can be passed as parameters for future computation.
Example of a Lambda expression:
In my previous blog post on extension methods, I demonstrated how you can declare a simple person class like the following:
Then, I demonstrated how you can use some values to generate an instance of a list <person> set, then, a new where and average extension method provided by LINQ is used to return a subset of the persons in the set and calculate the average age of the persons in the Set:
The highlighted red P => expression above is a Lambda expression. In the above example, I use the first Lambda to specify the filter conditions used to obtain a specific person, and the second Lambda to specify the value of the person object when calculating the average age.
Lambda expressions
The easiest way to understand lambda expressions is to think of them as a simple way to write in-row methods. For example, the example I wrote above can be written using the anonymous method of C #2.0, like this:
Both of the above anonymous methods accept a parameter of the person type. The first anonymous method returns a Boolean value, indicating whether the lastname of person is Guthrie, and the second anonymous method returns an integer (returning that person's age ). The Lambda expression we used previously has the same effect. Both expressions accept a parameter of the person type. The first Lambda expression returns a Boolean value, and the second returns an integer.
In C #, a Lambda expression is written as a parameter list in syntaxes, followed by a => symbol, followed by an expression or statement block to be computed during expression calling:
Params=>Expression
So when we write such a Lambda expression:
P => P. lastname = "Guthrie"
We want to indicate that we accept a parameter P in the defined lambda, and whether the value of P. lastname is equal to "Guthrie" is returned for the code expression to be run ". It is irrelevant to name the parameter P. I can also easily name it o, X, Foo, or any name I want.
Unlike anonymous methods, parameter types are explicitly specified. Lambda expressions allow parameter types to be omitted, while Lambda allows them to deduce types based on their usage. For example, when I write P => P. when the lambda expression lastname = "Guthrie" is used, the compiler infer that the p Parameter belongs to the person type, because the object of the current where extension method is a list <person> set of the model.
Lambda parameter types can be inferred from Visual Studio's intelliisense engine at compilation time, which means that you will get full intelliisense and compile-time check when writing lambda. For example, note that when I enter P. below, Visual Studio orcas provides intelliisense because it knows that P is of the person type:
Note: If you want to explicitly declare the parameter type for a Lambda expression, you can declare the parameter type before the parameter name in the lambda parameter table, as shown in the following code:
Advanced content for framework developers: Lambda Expression Tree (lambda expression trees)
From the perspective of a framework developer, one thing that makes lambda expressions particularly powerful is that, they can be compiled into code proxies (Code delegate) in the form of IL-based methods, or they can be compiled into an Expression Tree object, it is then used for analysis, conversion, or optimization during runtime.
Compiling a Lambda expression into an Expression Tree object is a powerful mechanism that will facilitate many application scenarios, this includes creating a high-performance object Er (relational database, Active Directory, or Web Service) that supports rich data queries using a unified query language that provides syntax check during compilation and vs intelliisense) capability.
Code delegates)
The above where extension method is an example of compiling a Lambda expression into a code proxy (that is, it is compiled into Il and can be called as a proxy ). The where () extension method that supports filtering any ienumerable set as above can be implemented using the following extension method code:
The above where () Extension Method acceptsFunc <t, bool>Type Filter parameter. this parameter is a proxy that accepts a T-type parameter and returns a Boolean value indicating whether the condition is met. When we pass the lambda expression as a parameter to this where () Extension Method, the C # compiler will compile Our lambda expression into the Il method proxy (here, <t> it will be person), and then our where () method can be called to calculate whether a given condition is met.
From lambda expressions to Expression Tree
When we want to perform operations on memory data similar to our list set, it is appropriate to compile the lambda expression into a code proxy. But consider the situation where you want to query the data in the database (the following code is written by using the built-in LINQ in orcas to the SQL Object Relational ER ):
Here, I want to retrieve a string of strong product objects from the database. I want to extend the method to where () and use a Lambda expression for filtering.
MeAbsolutely noTo see what happened, retrieve all product records from the database, place them in a local set, and then run where () on it in the memory () extension Method to filter. This is extremely inefficient, and the scalability of large databases will be very poor. What I want is that the ORM from LINQ to SQL translates the lambda filter conditions above into SQL expressions, and then performs filter queries in a remote database. In that case, I only return records that meet the query conditions. This database query efficiency is very high.
Framework developers can obtain such results by declaring that their Lambda expression parameters are of an expression <t> type rather than the func <t> type. This will cause Lambda expression parameters to be compiled into an expression tree that we can split and analyze at runtime:
Note how I previously used the same P => P. lastname = "Guthrie" Lambda expression, but assign it toExpression <func <person, bool>Variable insteadFunc <person, bool>Variable. The compiler will not generate Il, but will assign an Expression Tree object. Then, as a framework developer, I can use it to analyze the corresponding lambda expressions, calculate it as needed (for example, I can pick out the type, name, and value in the expression ).
In the case of writing a Lambda filter statement to SQL, it translates the lambda filter statement into a standard relational SQL statement to operate the database (logically speaking, A "select * from products where unitprice <55" Statement ).
Iqueryable <t> Interface
To help framework developers establish data providers that can be queried, LINQ provides the iqueryable <t> interface. This interface implements the standard query operator for the Extension Method of LINQ and provides a more convenient way to process a complex Expression Tree (for example, as shown below, I used 3 different extension methods and 2 Lambda to retrieve 10 products from the database ):
For more information about how to use iqueryable <t> to create a wonderful blog series of custom LINQ data providers, see the following blog posts written by others:
- LINQ to Amazon: Part 1, Part 2, Part 3
- LINQ to nhib.pdf: Part 1, Part 2, Part 3
- LINQ to LDAP: Part 1, Part 2, part 3, Part 4
Conclusion
I hope the above post provides a basic understanding of how to consider and use lambda expressions. When. when using the built-in standard query extension methods provided in the LINQ namespace for combination, they provide a very good way to query and interact with any type of data, at the same time, it also maintains support for the complete compile-time check and intelliisense.
By using Lambda's support for the Expression Tree and the iqueryable <t> interface, a data provider framework developer can ensure that the Code is clean, it runs fast and efficient on any data source (such as databases, XML files, in-memory objects, Web Services, and LDAP systems.
In the next few weeks, I will complete this series of languages that discuss new core language concepts at a theoretical level, then I will discuss some practical examples (especially for the use of LINQ for databases and XML files ).
I hope this article will help you,