Use reflector to see the "closure" clearly

Source: Internet
Author: User
Tags reflector

Today, Lao Zhao posted an article in the garden.Article"Be alert for variable sharing caused by anonymous methods", Immediately aroused widespread attention (Lao Zhao is the" popular king "of the garden, haha), and there are several other articles in the garden to study this problem.
For example"Closure","You are not commonly used in C #3: The strange action"

If you only stay at C #2.0/3.0"Simple and elegant"OfCodeIn terms of style, it is really difficult for beginners to understand this "strange" phenomenon. The first two days I bought this anytao "you must know. net, which provides a basic method to study this kind of "strange" phenomenon-il analysis, and recommends the well-known decompilation tool "reflector ", the following uses this tool to analyze it. (You don't have to read it. You can give it a reference for beginners)

Original code 1 (Excerpted from "You are not commonly used C #3": Strange action ):

Code 1
Using System;
Using System. Collections. Generic;

Namespace Consoletest
{
Class Program
{
Static   Void Main ( String [] ARGs)
{
List < Action > Ls =   New List < Action > ();
For ( Int I =   0 ; I <   10 ; I ++ )
{
Ls. Add (() => console. writeline (I);
}

Foreach(Action actionInLs)
{
Action ();
}
System. Console. Read ();
}
}

}

 

Result: 10 rows of exactly the same "10" are output in a row (the "intention" of the code writer may not be displayed, and 0 to 9 are output), why?

Open relector and make some settings:Open the "View" menu --> select "options", first remove the check box before show PDB symbols, and then change the optimization drop-down box to ". NET 1.0"(Many "syntactic sugar", such as anonymous methods and extension methods, appear after version 1.0. The purpose of this setting is to remove these gorgeous clothes, directly reflect the original C # code). After the code is decompiled, It is roughly as follows:

[Compilergenerated]
Private   Sealed   Class   <> C _ displayclass2
{
// Fields
Public   Int I;

//Methods
Public Void <Main>B _ 0 ()
{
Console. writeline (This. I );
}
}


Private   Static   Void Main ( String [] ARGs)
{
List < Action > List =   New List < Action > ();
Action item =   Null ;
<>C _ displayclass2 class2= New <> C _ displayclass2 ();
Class2. I= 0 ;
While(Class2. I< 10 )
{
If(Item= Null )
{
Item= NewAction (class2.<Main> B _ 0 );
}
List. Add (item );
Class2. I++ ;
}
Foreach (Action Action2 In List)
{
Action2 ();
}
Console. Read ();
}

As you can see,
1. the compiler automatically generates a seal class: <> C _ displayclass2, which contains a public field I and a public method <main> B _ 0 () -- used to output I
2. let's look at the highlighted section in the main method. from the beginning to the end, <> C _ displayclass2 generates only one instance class2. As for the while section below, it is changed, it is only changing the variable I (that is, the member I of the Instance class2), and we know that "class" is a reference type. Actually, class2 is just a reference, therefore, each time you use new action (class2. <main> B _ 0) to generate an item and then list it. after adding (item) is entered, each item calls the same reference. Therefore, 10 rows of the same result are output in a row. That is, the number 10 is taken for granted.

Modify code 1 as follows:

Using System;
Using System. Collections. Generic;

Namespace Consoletest
{
Class Program
{
Static   Void Main ( String [] ARGs)
{
List < Action > Ls =   New List < Action > ();
For ( Int I =   0 ; I <   10 ; I ++ )
{
  IntLp= I;
Ls. Add (() => console. writeline ( LP ));
}

foreach (action Action in ls)
{< br> action ();
}< br> system. console. read ();
}< BR >}

}that is, a temporary variable LP is used in the loop for a transit. The result of this operation outputs 10 different rows of 0-9 results on the screen. Why? Or use reflector to see what the final code is? [compilergenerated]
private sealed class <> C _ displayclass1
{< br> /// fields
Public int TP;

//Methods
Public Void <Main>B _ 0 ()
{
Console. writeline (This. Tp );
}
}

Private   Static   Void Main ( String [] ARGs)
{
List < Action > List =   New List < Action > ();
For(IntI= 0; I< 10; I++ )
{
<>C _ displayclass1 class2= New <> C _ displayclass1 ();
Class2.tp= I;
List. Add (NewAction (class2.<Main> B _ 0 ));
}
Foreach (Action action In List)
{
Action ();
}
Console. Read ();
} Similarly, the compiler automatically generates a sealed class for us, which is the same as that after code 1 is decompiled. Pay attention to the highlighted section, this time <> C _ displayclass1 class2 = new <> C _ displayclass1 (); is written in a loop, that is, 10 External loops go down, A total of 10 different C _ displayclass1 () Instances have been created, so you don't need to talk about the rest. You can see it. For this phenomenon, I personally think Lao Zhao's suggestion is very good: after the delegation is created, use it immediately -- No problem! (In fact, code 1 can also be changed to this way) After code 1 is modified
Using System;
Using System. Collections. Generic;
Namespace Consoletest
{
Class Program
{
Static   Void Main ( String [] ARGs)
{
List < Action > Ls =   New List < Action > ();
For ( Int I =   0 ; I <   10 ; I ++ )
{
Ls. Add (() => Console. writeline (I ));
Ls [I] ();
}

System. Console. Read ();
}
}
}

The result is normal and 0 to 9 are output. It is okay to verify "use now" again, but if it is not used immediately, you have to think about it more.Finally, the phenomenon mentioned in this article has been clearly explained by Lao Zhao. Here I just recommend the basic analysis method of decompilation to beginners (if you understand Il, can be analyzed more transparently), in many cases, simply lookProgramSuperficial phenomena are hard to understand. Using some tools, it is easier to find the essence under the appearance.

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.