From the evolution of delegate writing in. Net (medium): lambda expressions and their advantages

Source: Internet
Author: User

In the previous articleArticleWe briefly discuss the changes in delegate representations in. Net 1.x and. NET 2.0, as well as the advantages, objectives, and precautions of anonymous methods in. NET 2.0. Now let's talk about what the form of delegation has evolved into in. Net 3.5 (C #3.0) And what features and functions it has.

Delegate writing in. Net 3.5 (lambda expression)

Lambda expressions in C # are written as"Arg-list=>Expr-body"," => "Indicates the parameter list of the expression on the left and the body on the right ). The parameter list can contain 0 to multiple parameters, separated by commas. For example, Example 1 is defined using a Lambda expression:

 
Func<Int,Int,Int> Max = (IntA,IntB) => {If(A> B ){ReturnA ;}Else{ReturnB ;}};

The role of lambda expressions is the same as that of delegate to define an anonymous method. Therefore, the following uses the delegateCodeIt is equivalent to the above:

 
Func<Int,Int,Int> Max =Delegate(IntA,IntB ){If(A> B ){ReturnA ;}Else{ReturnB ;}};

Then you may ask, what does the lambda expression mean? Lambda expressions can be easily written. For example, lambda expressions can be abbreviated as follows:

Func<Int,Int,Int> Max = (a, B) => {If(A> B ){ReturnA ;}Else{ReturnB ;}};

Since we have already indicated that the max type is func <int, Int, int>, the C # compiler can clearly know that both A and B are of the int type, so we can save the type information before the parameter. This feature is called "type deduction", that is, the compiler can automatically know the type 2 of some members. Please do not think that this small improvement is of little significance. In fact, you will find that the advantages of lambda expressions are made up of 1.1 pieces of details. Then let's change again:

 
Func<Int,Int,Int> Max = (a, B) => A> B? A: B;

If the body of a Lambda expression is an expression rather than a statement, its body can omit braces and return keywords. In addition, if the lambda expression contains only one parameter, the brackets in the parameter list can also be omitted, as shown below:

 
Func<Int,Bool> Positive = A => A> 0;

Is it very simple to write today? Let's take a look at what it will look like if you use the delegate Keyword:

 
Func<Int,Bool> Positive =Delegate(IntA ){ReturnA> 0 ;};

You can immediately realize that, the difference between this line and the multi-line, the omission of these keywords and parentheses will make the programming world quite different at once.

Of course, lambda expressions do not completely replace the delegate method. For example, if an anonymous method with the ref and out keywords is used, you must use the delegate in. NET 2.0 to construct the method.

Example 1

Lambda expressions are enhanced by the word "Semantics. "Semantics" refers to the meaning of the Code. More commonly, it refers to the "feeling" that a piece of code gives readers. To illustrate this example, we still use the example to illustrate the problem.

The first example is as follows: "Please write a method, enter a list of strings that represent the integer type, and return a list containing the even square, and sort by the square result ". It's easy, isn't it? We believe that you can achieve it all at once:

 Static  List < Int > Getsquaresofpositive ( List < String > Strlist ){ List < Int > Intlist = New  List < Int > (); Foreach ( VaR S In Strlist) intlist. Add ( Int32 . Parse (s )); List < Int > Evenlist = New  List < Int > (); Foreach ( Int I In Intlist ){ If (I % 2 = 0) evenlist. Add (I );} List < Int > Squarelist = New  List < Int > (); Foreach ( Int I In Evenlist) squarelist. Add (I * I); squarelist. Sort (); Return Squarelist ;}

I would like to ask, what is the feeling of this code? It gives me the feeling that many things have been done. What are them?

    1. Create an integer list, and convert all elements in the strlist parameter to an integer type.
    2. Create an integer list evenlist and save the even number in intlist.
    3. Create an integer list squarelist and save the square of all numbers in the evenlist.
    4. Sort squarelist.
    5. Returns squarelist.

You may ask, "of course, what else can you do ?". In fact, if Lambda expressions are used, the code is much simpler:

 
StaticList<Int> Getsquaresofpositivebylambda (List<String> Strlist ){ReturnStrlist. Select (S =>Int32. Parse (s ))// Convert to an integer. Where (I => I % 2 = 0)// Find all the even numbers. Select (I => I * I)// Calculate the square of each number. Orderby (I => I)// Sort by element. Tolist ();// Construct a list}

In combination with the extension method defined in. Net 3.5, this code can be described as "in one breath" (in the actual coding process, Lao Zhao prefers to write this short "delivery" code into a line ). So what changes do the "Semantics" of this line of code have? Here, the change in "Semantics" is that the focus of code changes from "how to do" to "what to do ". This is the advantage of lambda expressions.

In the first method, we construct multiple containers, then perform some conversion, filtering, and populate the content with the container. In fact, these are all "how to do", that is, the so-called "How (to do )". But these codes do not directly represent what we want to do. What we want to do is actually "Get XXX", "filter out yyy", rather than "create container ", "Add element" and other operations.

In the implementation of lambda expressions, the Code has become much more declarative. The so-called "declarative" means "Claiming what the code is doing", rather than "how to operate the Code" in the "imperative" code ". In other words, "declarative" focuses on "what to do" and refers to "What (to do )". The semantics of the declarative code above is changed:

    1. Converts a string to an integer.
    2. Filter all even numbers
    3. Square each even number
    4. Sort by square result
    5. Generate a list

As for how to implement it, whether to construct a new container, and how to add elements to the container ...... The code using lambda expressions does not care about these details-this is not what we want to do. Why do we need to care about it?

Although the extension method is indispensable, I think lambda expressions are more important than the former, because they are responsible for the most critical "Semantics ". Imagine what it feels like "I => I * I? Is a delegate constructed? (of course, you must know that an anonymous method is constructed here )? At least for me, it means "turning I into I * I"; similarly, "I => I % 2 = 0" gives me the feeling that "(the filtering standard is) I mod 2 is equal to zero", instead of "constructing a delegate, xxx returns true, otherwise, false is returned. What's more interesting is that orderby (I => I) gives me the feeling that "sort I by myself ", instead of "A delegate that returns I itself ". All of this is to "declare" the Code in "what to do", rather than "how to do ".

Yes, "type deduction", "Parentheses omitted", and "Return keyword omitted" may all be "small" functions, however, these nuances have brought about a key change in encoding methods.

Example 2

Using lambda expressions can also save a lot of code (as you can see in the first example ). However, I think the most code-saving part should be its functions such as "grouping" and "dictionary conversion. So let's look at the second example.

This example may be closer to reality. I wonder whether you have followed the "Index" behind some books. It is actually "listing all the keywords, grouping according to the first letter, and sorting the keywords in each group ". To put it simply, we need the following method:

 
StaticDictionary<Char,List<String> Getindex (Ienumerable<String> Keywords ){...}

What do you do? In fact, it is not difficult (for example, we only focus on lower-case English, and do not care about repeated keywords ):

 Static  Dictionary < Char , List <String > Getindex ( Ienumerable < String > Keywords ){ // Define the dictionary  VaR Result = New  Dictionary < Char , List < String >> (); // Fill the dictionary  Foreach ( VaR KW In Keywords ){ VaR Firstchar = Kw [0]; List < String > Groupkeywords; If (! Result. trygetvalue (firstchar, Out Groupkeywords) {groupkeywords = New  List < String > (); Result. Add (firstchar, groupkeywords);} groupkeywords. Add (kW );} // Sort each group  Foreach ( VaR Groupkeywords In Result. Values) {groupkeywords. Sort ();} Return Result ;}

So what will the Code become if Lambda expressions and the extension methods defined in the. NET Framework are used? See:

StaticDictionary<Char,List<String> Getindexbylambda (Ienumerable<String> Keywords ){ReturnKeywords. groupby (k => K [0])// Group by the first letter. Todictionary (// Construct a dictionaryG => G. Key,// Use the key of each group as the keyG => G. orderby (k => K). tolist ());// Sort each group and generate a list}

In terms of the number of codes, the former is several times that of the latter. However, the advantages of readability such as declarative and what are no longer repeated. I personally think it is better than the "Shock" given by the previous example.

Imagine how to change the lambda expression in the getindexbylambda Method to the delegate format in. NET 2.0:

 Static Dictionary < Char , List < String > Getindexbydelegate ( Ienumerable < String > Keywords ){ Return Keywords. groupby ( Delegate ( String K ){ Return K [0];}). todictionary ( Delegate ( Igrouping <Char , String > G ){ Return G. Key ;}, Delegate ( Igrouping < Char , String > G ){ Return G. orderby ( Delegate ( String S ){ Return S ;}). tolist ();});}

Are you willing to write such code?

Therefore, lambda expressions play a decisive role here. In fact, it is because of lambda expressions that some functional programming features in. NET are truly popularized. The "language features" determine the "programming method. In this regard, Java is a good counterexample: theoretically, Java also has the "inline" writing method, but the pleasure of using C # can only be a dream in Java. Imagine what happens to getindexbylambda in Java 3:

 Public Dictionary <char, list <string> getindexinjava (enumerable <string> keywords ){ Return Keywords. groupby ( New Func <string, char> { Public Char execute (string s ){ Return S. charat (0) ;}}). todictionary ( New Func <grouping <char, string>, char> {Public Char execute (igrouping <char, string> G ){ Return G. getkey ();}}, New Func <grouping <char, string>, list <string >> { Public List <string> execute (igrouping <char, string> G ){ Return G. orderby ( New Func <string, string> { Public String execute (string s ){ Return S ;}}). tolist ();}});}

A sense of syntactic noise is overwhelming. Because of the anonymous type syntax in Java (that is, the above inline writing method), the connection type information (New func <string, char> {...} such code) can not be omitted, so it gives people a very tedious feeling. In the face of such code, you may have the same idea as me: "It's not as common as writing ". Yes, this functional programming style is not suitable for Java due to lack of language support. As a matter of fact, this kind of inline writing has long appeared (at least in the 02 and 03 years when I was still using Java), but it has not been improved for so many years. When a Lambda expression appears,CommunityFollowed up on a large number of projects, such as Moq and fluent nhib.pdf, and made full use of this new feature of C #3.0. Isn't this enough to explain the problem?

By the way, we recommend Scala again. Its code can be as beautiful as C. I am not a fan of the Java platform, but a loyal opponent of the Java language, but I have a strong liking for Scala and open-source projects on the Java platform.

Now that we have talked about functional programming, let's say a few more. In fact, both examples have strong functional programming shadows. For example, for function test programming, where is often called filter, and select is often called map. Other methods defined in. Net 3.5 are embodied in functional programming (for example, aggregate is equivalent to fold ). If you are interested in this, follow the functional C # class library proposed by Matthew poswysocki.

Summary

It not only improves readability, but also reduces the number of code. I can't find any reason to reject lambda expressions.

Oh, by the way, you may mention "performance", which is indeed an important aspect, but we will discuss this topic next time. Due to space limitations, the two originally planned "upper" and "lower" articles had to be split again this time. As for other content, let's talk about it later.

Of course, nothing in the world is perfect. If you think lambda expressions may bring "harm" to you in some cases, you may also use delegate instead of lambda expressions. For example, to make the code clearer, it is better to explicitly specify the parameter type in some cases. However, for me, in any situation, I will use a Lambda expression-a maximum of "(int A, string B) =>, I think it is more unified and easier than "Delegate (int A, string B.

Related Articles
    • From the evolution of delegate writing in. Net (I): Delegate and anonymous methods
    • From the evolution of delegate writing in. Net (medium): lambda expressions and their advantages
    • From the evolution of delegate writing in. Net (II): performance-related

 

Note 1:Strictly speaking, the body here is a "statement" instead of "expression )". Because a delegate is actually a method, lambda is used to represent a delegate, which must contain "statements ". However, in the current C #, lambda expressions can also be used to construct an "Expression Tree". Currently, the C # compiler can only construct an "Expression Tree" instead of "Statement tree ".

NOTE 2:In fact. NET 2.0, when using the delegate keyword to define an anonymous method, the meaning of "type deduction" can be introduced. Although the parameter type must be specified, We can omit the delegate type, isn't it?

NOTE 3:Unless we add func, enumerable, Dictionary, grouping, and Other Types and APIs, this Code cannot be compiled in Java. In fact, I wrote this Java code in notepad. However, this form is completely correct.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.