Understand the closure in C #

Source: Internet
Author: User

The internal function of the closure can reference the variable of the function contained in its outer layer, even if the execution of the outer function has been terminated. However, the value provided by the variable is not the value at the time of creation, but the final value within the range of the parent function. The advantages of closures use closures, so that we can easily access variables defined by the outer function, which is widely used in anonymous methods. For example, in the following scenario, we want to make such an effect in the winform application. When the user closes the form, a prompt box is provided to the user. We will add the following code: copy the code private void Form1_Load (object sender, EventArgs e) {string tipWords = "You will close the current dialog box"; this. formClosing + = delegate {MessageBox. show (tipWords) ;};} if you do not use anonymous functions, you need to use other methods to pass the tipWords variable value to the processing function registered by FormClosing, this increases unnecessary workload. Closure trap application closure, we should pay attention to a trap. For example, if there is an array of user information, we need to traverse each user and output the user name after processing each user. Copy the public class UserModel {public string UserName {get; set;} public int UserAge {get; set ;}} code ;}} copy code copy code List <UserModel> userList = new List <UserModel> {new UserModel {UserName = "jiejiep", UserAge = 26}, new UserModel {UserName = "xiaoyi ", userAge = 25}, new UserModel {UserName = "zhangzetian", UserAge = 24 }}; foreach (var u in userList) {ThreadPool. queueUserWorkItem (obj) =>{// TODO // Do some proce Ss... //... thread. sleep (1000); MessageBox. show (u. userName) ;});} the expected output of the copied code is: jiejiep, xiaoyi, zhangzetian. However, after we run the code, we found that three times of zhangzetian was output. why didn't we achieve the expected results? Let's take a look at the concept of closures. The final value of the variable of the outer function referenced by the inner function. That is to say, when the thread executes a method, the value of the u parameter in the method is always the last element of foreach traversal. So, how can we avoid the closure trap? The common practice in C # Is to save the variables referenced by the anonymous function with a temporary variable, and then use the temporary variable in the anonymous function. Copy the code foreach (var u in userList) {UserModel tempUser = u; ThreadPool. queueUserWorkItem (obj) =>{// TODO // Do some process... //... thread. sleep (1000); MessageBox. show (tempUser. userName) ;});} copy the code and run it again. The output is the jiejiep, xiaoyi, zhangzetian NET compiler and closure, and a solution is provided, we finally know how to use the closure correctly. But how does dotNET implement closures? Persistent programmers are not satisfied with this kind of solution. Let's look at how dotNET implements closures. We can use isdasm.exe to view the compiled code. Let's take a look at the problematic code. After translating the IL code, you can get the following pseudocode. Copy the public class TempClass {public UserModel um {get; set;} public void ShowMessage (object obj) {Thread. sleep (1000); MessageBox. show (um. userName) ;}} copy the code copy code TempClass tempCls = new TempClass (); foreach (var u in userList) {tempCls. um = u; ThreadPool. queueUserWorkItem (obj) =>{ tempCls. showMessage (obj) ;}}copy the original code. The Compiler generates a temporary class for us, which contains a UserModel member um and an instance method ShowMessage (object ). Let's take a look at the code in the traversal part, and we suddenly become very open. Originally, there was only one TempClass instance, and the time change was always the value of the um field of the tempCls object. Therefore, the final output is always the UserName of the last retrieved element. Let's take a look at the code after using a temporary variable. How does the compiler handle it. Copy the code foreach (var u in userList) {TempClass tempCls = new TempClass (); tempCls. um = u; ThreadPool. queueUserWorkItem (obj) =>{ tempCls. showMessage (obj) ;});} copy the code and we can see that when temporary variables are used in this solution, the compiler instantiated A TempClass object every time. Therefore, the um members of the tempCls referenced by the inner function always traverse the corresponding elements. Therefore, it can effectively solve the traps brought about by closures.

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.