Impact of closures
To show the impact of the closure, let's look at the example below.
VaR Buttons = New Button [ 10 ]; For ( VaR I = 0 ; I <buttons. length; I ++ ){ VaR Button = New Button (); button. Text = (I + 1 ) + " . Button-click for index! " ; Button. onclick + = (S, e) => {MessageBox. Show (I. tostring () ;}; buttons [I] = Button ;} // What will happen if we click the button?
This is a strange question. I often ask my students in my JavaScript courses. 95% of students said. Obviously, the button 0 shows 0, the button 1 shows 1, and so on. Less than 5% of students will understand after learning the closure. 10 is displayed for all buttons.
The value of the local variable I has changed. And is equal to buttons. length. That is, 10. It's easy to avoid this strange situation. As shown in the following figure.
VaRButton =NewButton ();VaRIndex =I; button. Text= (I +1) +". Button-click for index!"; Button. onclick+ = (S, e) =>{MessageBox. Show (index. tostring () ;}; buttons [I]= Button;
The problem is solved, but the index variable is a value type, so a copy of "global" I is retained.
The last topic is something called the expression tree. It cooperates with Lambda expressions. In addition, he will make some wonderful things happen in the HTML Extension Method in ASP. net mvc. The key issue is: how to find the target function
1. What is the name of the variable passed in?
2. What is the subject of the method?
3. What types are used in the function body?
Expression solves these problems. It allows us to mine the generated Expression Tree. We can also execute the functions that are passed to func and action delegates, and parse lambda expressions at runtime.
Let's take a look at how to use the expression type example.
Expression <func <mymodel,Int> Expr = model =>Model. myproperty;VaRMember = expr. BodyAsMemberexpression;VaRPropertyname = memberexpression. member. Name;//When member! = Execution when null...
This is the simplest use of expression. The rules are also quite straightforward. Construct an expression-type object. The compiler generates some metadata for the generated interpretation tree. This interpretation tree contains all relevant information, such as parameters and method bodies.
The method body contains a complete interpretation tree, which we can access. Just like a complete statement. You can also specify the return value and type. Of course, the return value can be null. In most cases. We are very interested in expressions. This is very similar to the expression-type method in ASP. net mvc-the name of the parameter to be used can be obtained, and the benefit is obvious. No name spelling errors will occur. This will not cause any compilation errors.
Note: WhenProgramThe caller is only interested in the name of the called attribute. There is a simpler and more elegant solution, that is, the parameter feature callermembername can get the name of the call method/attribute. The field is automatically filled by the compiler. Therefore, if we only want to know the name and do not want to know more information, we only need to writeCodeThat's all. You can call the whatsmyname () method to return the method name.
StringWhatsmyname ([callermembername]StringCallingname =Null){ReturnCallingname ;}
Performance of lambda expressions
There is a big question: How fast is a Lambda expression? Okay. First, we expect them to be as fast as our general functions. In the next section. The msil code of Lambda is not very different from that of a common function.
One of the most interesting discussions is that if a Lambda expression produces a closure, it will be as fast as using a global variable method. This creates an interesting question. Is it related to the number of local variables in a region?
Let's look at the test code. With four different indicators, we can see the differences between common methods and Lambda methods.
Using System; Using System. Collections. Generic; Using System. diagnostics; Namespace Lambdatests { Class Standardbenchmark: benchmark { Const Int Length = 100000 ; Static Double []; Static Double [] B; Static Void Init (){ VaR R = New Random (); = New Double [Length]; B = New Double [Length]; For ( VaR I = 0 ; I <length; I ++ ) {A [I] = R. nextdouble (); B [I] = R. nextdouble ();}} Static Long Lambdabenchmark () {func < Double > Perform = () =>{ VaR Sum = 0.0 ; For ( VaR I = 0 ; I <length; I ++ ) Sum + = A [I] * B [I]; Return SUM ;}; VaR Iterations = New Double [ 100 ]; VaR Timing = New Stopwatch (); timing. Start (); For ( VaR J = 0 ; J <iterations. length; j ++ ) Iterations [J] = Perform (); timing. Stop (); console. writeline ( " Time for Lambda-benchmark: \ t {0} MS " , Timing. elapsedmilliseconds ); Return Timing. elapsedmilliseconds ;} Static Long Normalbenchmark (){ VaR Iterations = New Double [ 100 ]; VaR Timing =New Stopwatch (); timing. Start (); For ( VaR J = 0 ; J <iterations. length; j ++ ) Iterations [J] = Normalperform (); timing. Stop (); console. writeline ( " Time for normal-benchmark: \ t {0} MS " , Timing. elapsedmilliseconds ); Return Timing. elapsedmilliseconds ;} Static Double Normalperform (){ VaR Sum = 0.0 ; For ( VaR I = 0 ; I <length; I ++ ) Sum + = A [I] * B [I]; Return Sum ;}}}
We can use lambda expressions to write better code. In the end, I did not. It is to prevent impact on the final result. Therefore, essentially. There are three methods in the above Code
One is lambda testing, the other is normal testing, and the other is the method called in normal testing. The fourth method is actually our Lambda expression. It has been created in the first method. The calculation process is very simple. We randomly take numbers to prevent the compiler from doing any optimization. Finally, we are very interested in the differences between common methods and Lambda methods.
If we run this test program. We will find that Lambda expressions are not always worse than normal methods. We are surprised that sometimes even lambda expressions are faster. However, in the case of closures, it is incorrect. This means that in most cases, we can use lambda expressions without hesitation. When using closures, there will be a little performance loss, but fortunately, the next section will explain several causes of performance loss.
The following table lists the test output results.
Test Lambda [MS] Normal [MS]
0 45 +-1 46 +-1
1 44 +-1 46 +-2
2 49 +-3 45 +-2
3 48 +-2 45 +-2
Is the result of the above table. We can see that the general method is basically the same as the lambda expression limit. When lambda expressions are used, there is not much performance loss.
The secrets behind Chapter 3-msil