Improving coding efficiency in the special topics of Linq -- Article 3 enumeration classes you need to know:

Source: Internet
Author: User
Tags mscorlib

Improving coding efficiency in the special topics of Linq -- Article 3 enumeration classes you need to know:

 

As we all know, if a class can be enumerated, this class must implement the IEnumerable interface, while all of our linq classes are anonymous classes inherited from the IEnumerable interface,

Then the question is, how can IEnumerable enable these set types to be freely enumerated ???

 

I. Exploring IEnumerable

First, let's see what this interface defines, as shown in ILSpy:

 

From this interface, it seems that there is only one method of the IEnumerator interface type, and there is nothing that can be mined. In this case, you should be curious. Since foreach can enumerate Collection,

What is the relationship between the mechanism behind foreach and GetEnumerator ??? Let's write a demo and use ILDasm to check the IL behind it.

 

C # code:

     static void Main(string[] args)        {            List<Action> list = new List<Action>();            foreach (var item in list)            {                Console.WriteLine();            }        }

 

IL code:

.method private hidebysig static void  Main(string[] args) cil managed{  .entrypoint  // Code size       60 (0x3c)  .maxstack  1  .locals init ([0] class [mscorlib]System.Collections.Generic.List`1<class [mscorlib]System.Action> list,           [1] valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<class [mscorlib]System.Action> V_1,           [2] class [mscorlib]System.Action item)  IL_0000:  nop  IL_0001:  newobj     instance void class [mscorlib]System.Collections.Generic.List`1<class [mscorlib]System.Action>::.ctor()  IL_0006:  stloc.0  IL_0007:  nop  IL_0008:  ldloc.0  IL_0009:  callvirt   instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<class [mscorlib]System.Action>::GetEnumerator()  IL_000e:  stloc.1  .try  {    IL_000f:  br.s       IL_0021    IL_0011:  ldloca.s   V_1    IL_0013:  call       instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<class [mscorlib]System.Action>::get_Current()    IL_0018:  stloc.2    IL_0019:  nop    IL_001a:  call       void [mscorlib]System.Console::WriteLine()    IL_001f:  nop    IL_0020:  nop    IL_0021:  ldloca.s   V_1    IL_0023:  call       instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<class [mscorlib]System.Action>::MoveNext()    IL_0028:  brtrue.s   IL_0011    IL_002a:  leave.s    IL_003b  }  // end .try  finally  {    IL_002c:  ldloca.s   V_1    IL_002e:  constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<class [mscorlib]System.Action>    IL_0034:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()    IL_0039:  nop    IL_003a:  endfinally  }  // end handler  IL_003b:  ret} // end of method Program::Main

 

From the perspective of the red font marked by IL, the so-called foreach essentially calls the GetEnumerator () method of list to return an Enumerator Enumeration type, and then passes

Current gets the current value, and then uses MoveNext () to get the next value, and so on. If you restore IL, it is like the following:

            var enumerator = list.GetEnumerator();            try            {                while (enumerator.MoveNext())                {                    Console.WriteLine(enumerator.Current);                }            }            finally            {                enumerator.Dispose();            }

 

At this time, do you have a strong desire to explore what GetEnumerator () has done and what role does MoveNext () play in it ??? Let's use ILSpy to check the List below.

The so-called Enumerator type...

 

 1     [Serializable] 2         public struct Enumerator : IEnumerator<T>, IDisposable, IEnumerator 3         { 4             private List<T> list; 5             private int index; 6             private int version; 7             private T current; 8             [__DynamicallyInvokable] 9             public T Current10             {11                 [__DynamicallyInvokable]12                 get13                 {14                     return this.current;15                 }16             }17             [__DynamicallyInvokable]18             object IEnumerator.Current19             {20                 [__DynamicallyInvokable]21                 get22                 {23                     if (this.index == 0 || this.index == this.list._size + 1)24                     {25                         ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumOpCantHappen);26                     }27                     return this.Current;28                 }29             }30             internal Enumerator(List<T> list)31             {32                 this.list = list;33                 this.index = 0;34                 this.version = list._version;35                 this.current = default(T);36             }37             [__DynamicallyInvokable]38             public void Dispose()39             {40             }41             [__DynamicallyInvokable]42             public bool MoveNext()43             {44                 List<T> list = this.list;45                 if (this.version == list._version && this.index < list._size)46                 {47                     this.current = list._items[this.index];48                     this.index++;49                     return true;50                 }51                 return this.MoveNextRare();52             }53             private bool MoveNextRare()54             {55                 if (this.version != this.list._version)56                 {57                     ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);58                 }59                 this.index = this.list._size + 1;60                 this.current = default(T);61                 return false;62             }63             [__DynamicallyInvokable]64             void IEnumerator.Reset()65             {66                 if (this.version != this.list._version)67                 {68                     ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);69                 }70                 this.index = 0;71                 this.current = default(T);72             }73         }

 

By looking at the definition of the so-called Enumerator class, especially the red mark, you may be enlightened. In fact, the so-called enumeration class is just a packaging class of an enumeration set, for example, the List,

Then, the enumeration class uses index ++ to obtain the elements in the List one by one. That's all.

 

Ii. yield keywords

After you understand the so-called enumeration class, do you think of a weird yield lexical function? This can still be enumerated, for example, the following code:

 1 class Program 2 { 3     static void Main(string[] args) 4     { 5         foreach (var item in Person.Run()) 6         { 7             Console.WriteLine(item); 8         } 9 10     }11 }12 13 class Person14 {15     public static IEnumerable<int> Run()16     {17         List<int> list = new List<int>();18 19         foreach (var item in list)20         {21             yield return item;22         }23     }24 }

 

So what exactly does yield do? In addition, it allows people to find out what is actually ??? Let's take a look at it using ILDasm.

 

Take a closer look at the code above. The so-called yield will generate an enumeration class for you, which is very similar to the Enumerator enumeration class in the List just now. If you understand the display

Enumerator of the enumeration class. I think this anonymous enumeration class Enumerator should be very simple.

 

Well, that's probably the case. With this foundation, I believe that the Anonymous Enumeration classes returned in linq will be okay for you ~~~

 

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.