C # Delegate, anonymous method and Lambda expression)

Source: Internet
Author: User

in. in. net, delegation, anonymous methods, and lambda expressions are three confusing concepts. the following Code can be seen: Which of the following code will be compiled in the first call? Which ones will return the expected answers? (Customer with ID 5 ). in fact, the answer is: all the six methods will not be compiled, and they can all return normal customers, which are functionally the same. if you are still asking yourself: Why? This Article will answer you.

class customer
{< br> Public int ID { Get ; set ;}< br> Public static bool test (Customer X)
{< br> return X. id = 5;
}< BR >}< br>...
List custs = New List ();
custs. add ( New customer () {id = 1});
custs. add ( New customer () {id = 5});

Custs. First (NewFunc <customer,Bool> (Delegate(Customer X ){ReturnX. ID = 5 ;}));
Custs. First (NewFunc <customer,Bool> (Customer X) => X. ID = 5 ));
Custs. First (Delegate(Customer X ){ReturnX. ID = 5 ;});
Custs. First (Customer X) => X. ID = 5 );
Custs. First (x => X. ID = 5 );
Custs. First (customer. test );

1. What is delegation?

For example, we suppose there is a shopping cart class used to process the order of the customer ). the manager decides to discount customers who exceed a certain amount or the amount of purchases. therefore, you must use their policies to calculate orders. this is not difficult: You simply declare a variable to save the discount and call it when calculating the order amount.

ClassProgram {Static VoidMain (String[] ARGs ){NewShoppingcart (). Process ();}}ClassShoppingcart {Public VoidProcess (){IntMagicdiscount = 5;//...}}

However, the next day, the savvy manager decided to give a discount based on the time of the day. Well, it's not hard. You just need to change the code:

ClassShoppingcart {Public VoidProcess (){IntMagicdiscount = 5;If(Datetime. Now. Hour <12) {magicdiscount = 10 ;}}}

In the next few days, the manager has repeatedly increased or modified the Discount calculation method! How can I handle and maintain this seemingly absurd logic? In fact, all you need to do is "Hand over" or "delegate" the responsibility to others. in. net, there is such a mechanism, I do not say you have to guess, that is, "Commission ".

Ii. Delegation

If you have a C/C ++ background, the function pointer is the best description delegate. for average people, it can be considered as a way to pass methods like common parameters. for example, the following three lines of code reflect the same basic principles:Process MethodPass a piece of data without using it.

// Passing an integer value for the process method to useProcess (5 );// Passing a reference to an arraylist object for the process method to useProcess (NewArraylist ());// Passing a method reference for the Process Method to callProcess (discountdelegate );

So, the aboveWhat is discountdelegate? How can we create it? How does the process method use it? First, we need to declare a delegate type, just as we declare a class.

 
Delegate IntDiscountdelegate ();

This Code gives usDiscountdelegate delegate. We can use it like a class and a structure. this delegate has no parameters and only one int type return value. like a class, we cannot use it before creating any of its instances. when instantiating a delegate, you must note that the delegate is only a reference of a method, even ifDiscountdelegate does not have any constructor. When it is instantiated, there will be a hidden Constructor (No parameter but int value is returned). How can we give this constructor a method? OK. In. net, you only need to enter the name of the method you want to call. The brackets behind the method name are omitted.

Discountdelegate discount =NewDiscountdelegate (Class. Method );

Before further discussion, let's look back at the previous example. We will addCalculatorClass to help us calculate the discount, and design some methods to provide for delegated reference.

 Delegate   Int Discountdelegate (); Class Program { Static   Void Main ( String [] ARGs) {calculator calc = New Calculator (); discountdelegate discount = Null ; If (Datetime. Now. Hour <12) {discount = New Discountdelegate (Calc. Morning );} Else   If (Datetime. Now. Hour <20) {discount = New Discountdelegate (Calc. afternoon );} Else {Discount = New Discountdelegate (Calc. Night );} New Shoppingcart (). Process (discount );}} Class Calculator { Public  Int Morning (){ Return 5 ;} Public   Int Afternoon (){ Return 10 ;} Public   Int Night (){ Return 15 ;}} Class Shoppingcart { Public   Void Process (discountdelegate discount ){ Int Magicdiscount = discount (); //... }}

As we can seeCalculatorClass creates a method for the calculation logic of each discount. In the main methodCalculator class andDiscountdelegateWe have created an instance to serve the target method we will call.

So far, we are no longerProcessThe computing logic in the method is worrying. We can simply call the delegate to complete it. but remember: We don't care about how and when this delegate was created. we only call it when we need it, just like calling other methods. it can be seen that the delegate can also be understood as delaying method execution. the real calculation method is when we callThe discount () method can be executed. Check the above code again.CalculatorClass, can we use a method to provide all return values? Of course. Let's make improvements together.

 Delegate   Int Discountdelegate (); Class Program { Static   Void Main (String [] ARGs ){ New Shoppingcart (). Process ( New Discountdelegate (calculator. Calculate ));}} Class Calculator { Public   Static   Int Calculate (){ Int Discount = 0; If (Datetime. Now. Hour <12) {discount = 5 ;} Else   If (Datetime. Now. Hour <20) {discount = 10 ;} Else {Discount = 15 ;} Return Discount ;}} Class Shoppingcart { Public   Void Process (discountdelegate discount ){ Int Magicdiscount = discount (); //... }}

Now, let's do it. StaticCalculateMethod makes the class much refreshed. The main method does not have so manyDiscountdelegateNow, we have some knowledge about delegation.

3. We need such a feature!

In. NET 2.0, the concept of generics was introduced. Ms carefully providedAction <t> class to move towards generic configuration. then, I think, some time later, it was forgotten by most of us. later, at 3.5, Ms provided us with some common authorizations, So we no longer need to define our own delegated permissions. they also extended the action and added func. the only difference between action and func is that the former does not return values, while the latter does.

That is to say, we no longer need to declareDiscountdelegate, We can useFunc <int>To replace it. to demonstrate how parameters work, let's assume that the manager has changed the Discount calculation logic again: Now, we need to record a special discount. this is also a piece of cake, we just needCalculateYou can call a Boolean value in the method.

In this way, our original non-parameter delegation becomesFunc <bool, int> format. Note that the currentCalculateThe method has a Boolean parameter.DiscountIt must be included.

 Class Program { Static   Void Main ( String [] ARGs ){ New Shoppingcart (). Process (New Func < Bool , Int > (Calculator. Calculate ));}} Class Calculator { Public   Static   Int Calculate ( Bool Special ){ Int Discount = 0; If (Datetime. Now. Hour <12) {discount = 5 ;} Else   If (Datetime. Now. Hour <20) {discount = 10 ;} Else   If (Special) {discount = 20 ;} Else {Discount = 15 ;} Return Discount ;}} Class Shoppingcart { Public   Void Process (func < Bool , Int > Discount ){ Int Magicdiscount = discount (False ); Int Magicdiscount2 = discount ( True );}}

This is a good idea. How many lines of code are saved, isn't it? Of course not. If we use the type interface, we can save more code and time.The creation process of func <bool, int>, as long as this method has the same parameters and return values as we expected delegate.

 
// Works because process expects a method that takes a bool and returns intNewShoppingcart (). Process (calculator. Calculate );

Based on this, we omitted the custom delegate and skipped the direct creation of the func delegate later, saving a lot of code. Is there any way to reduce the amount of code? Of course, this is because we have mentioned half of this article.

Iv. Anonymous Method

The anonymous method allows us to declare a method without a name. in the background, there is a method named 'normal. however, in code, we cannot explicitly call this method. Anonymous methods can only be created and used when the delegate is used and the delegate keyword is used. for example:

ClassProgram {Static VoidMain (String[] ARGs ){NewShoppingcart (). Process (NewFunc <Bool,Int> (Delegate(BoolX ){ReturnX? 10: 5 ;}));}}

We can see from the above: we do not needCalculatorClass. you can enter more small logic into the branch of curly braces, just as you used in other methods. if you find it hard to understand the working process of this Code, assume thatDelegate (bool X)Is a method signature rather than a delegate keyword. Put this code in a class,Delegate (bool X) {return 5 ;}It is a special declaration of the logical computing method (which should be of the return value type). It is easy to understand this.DelegateIt only hides the name of the original method.

Well, I believe we can omit more code so far. naturally, we can ignore the display statement of the func delegate. When we use the delegate keyword ,. net will handle everything for us.

 
ClassProgram {Static VoidMain (String[] ARGs ){NewShoppingcart (). Process (Delegate(BoolX ){ReturnX? 10: 5 ;});}}

In. net, when the method expects a delegate as a parameter and responds to the event, the real power of the anonymous method can be seen. previously, we had to create a method for every possible action. now, we only need a line of statements, and will not "pollute" The namespace.

// Creates an anonymous comparerCusts. Sort (Delegate(Customer C1, customer C2 ){ReturnComparer <Int>. Default. Compare (c1.id, c2.id );});// Creates an anonymous event handlerButton1.click + =Delegate(ObjectO, eventargs e) {MessageBox. Show ("Click!");};
5. Lambda expressions Lambda expressions are anonymous functions that can contain expressions and statements and can be used to create a delegate or Expression Tree. we need to understand how lambda expressions play in the "Create delegate" section? Well, in fact, the expression and Expression Tree are beyond the scope of our explanation. We only need to know that the expression is. net. Program Data or object code. the Expression Tree is a logical expression that allows other code to "ask. when a Lambda expression is converted to an Expression Tree, the editor does not generate new il code. The Expression Tree and Lambda expression represent the same logic.

We need to pay attention to the following: replacing anonymous methods with Lambda expressions and adding new features. looking back at our last example, we have removed a lot of code on the basis of the initial creation and wrote the Discount calculation logic to a row.

 
ClassProgram {Static VoidMain (String[] ARGs ){NewShoppingcart (). Process (Delegate(BoolX ){ReturnX? 10: 5 ;});}}

Do you believe we can make it shorter? Lambda expressions use the "=>" symbol to represent "the parameter is passed to the expression". When the compiler encounters this symbol, it will allow us to ignore the parameter type, and deduce the type for us. if there are two or more parameters, you can use parentheses:(X, y) =>. If there is only one, it will be like this:X =>.

Static VoidMain (String[] ARGs) {func <Bool,Int> Del = x => X? 10: 5;NewShoppingcart (). Process (DEL );}// Even shorter...Static VoidMain (String[] ARGs ){NewShoppingcart (). Process (x => X? 10: 5 );}

Yes, that is, the. X is inferred as Boolean, And the return value type is the same.ProcessThere isFunc <bool, int> type parameter. If you want to execute this code as before, you only need to add the branch.

Static VoidMain (String[] ARGs ){NewShoppingcart (). Process (x => {IntDiscount = 0;If(Datetime. Now. Hour <12) {discount = 5 ;}Else If(Datetime. Now. Hour <20) {discount = 10 ;}Else If(X) {discount = 20 ;}Else{Discount = 15 ;}ReturnDiscount ;});}
6. Last thing

There is a big difference in the use of branching. when you use it, it is equivalent to creating a "Statement-based Lambda". On the contrary, it is an "expression-based Lambda ", the former can execute multi-line statements according to the requirements of the branch, but cannot create an Expression Tree. when we are usingIqueryableThis problem may occur during interface operations. The following example shows this problem"

List < String > List = New List < String > (); Iqueryable < String > Query = List. asqueryable (); list. Add (" One "); List. Add (" Two "); List. Add (" Three "); String Foo = List. First (x => X. endswith (" O "));String Bar = query. First (x => X. endswith (" O ")); // Foo and bar are now both 'two' as expected Foo = List. First (x => { Return X. endswith (" E ");}); // No error Bar = query. First (x => { Return X. endswith (" E ");}); // Error Bar = query. First (func < String , Bool >) (X => {Return X. endswith (" E ");})); // No error 

An error occurred while editing the second bar value. This is becauseIqueryable. FirstExpect an expression as a parameter. However, the expression methodList <t>. FirstIn this case, a delegate is expected. You can forcibly convert the value of the lambda expression to delegate, as in the third time above.

There are still many things to be written here, but I think I have to end this article. lambda is basically divided into two types: one is to create an anonymous method and the other is to create an expression.

VII. Summary

I hope this article will help you solve the first six obfuscation-related delegation, anonymous methods, and Lambda expression call problems.

<End>

Related Article

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.