Categories
Uncategorized

Iterator pattern Caprice

First, what is the iterator pattern?

Definition: A method for providing sequential access to the collection without exposing the interior of the collection represents

Sequential access, one by one (one by one access), does not expose the inner set of said reflecting encapsulation in object-oriented programming. It can be understood, a group of models appeared from backstage, one by one, but the first appearance of the model, may not be standing in front of a model. In other words, for the audience, you do not know the specific location of the background models. Why is sequential access it? Because the output mechanism is used in an iterative mode good internal decision, you can not decide. Unlike a dictionary, I preach a different key, you can access different value. We access list, direct access to the i-th element, but the iterator, after the next you want to access an element, the element must be current visit, to get to the next element.

Two, c # iterators Interface

 

Iterator interface, can be achieved manually invoked, as follows:

 1     public class MyIEnumerator : IEnumerator<string>
 2     {
 3         string[] types = { "

Inferior horse

", "

Fine horse

", "

Medium horse

" }; 4 5 int cur = -1; 6 public string Current 7 { 8 get 9 { 10 return types[cur]; 11 } 12 } 13 object IEnumerator.Current 14 { 15 get 16 { 17 return this.Current; 18 } 19 } 20 21 public void Dispose() 22 { 23 } 24 25 public bool MoveNext() 26 { 27 if (cur < types.Length - 1) 28 { 29 cur++; 30 return true; 31 } 32 return false; 33 } 34 35 public void Reset() 36 { 37 cur = -1; 38 } 39 }

Tian Ji’s horse as saying, according to a certain order of appearance won the king of Qi, this policy was proposed by Sun Bin, and then look at the call:

1      MyIEnumerator m = new MyIEnumerator();
2      while (true)
3       {
4           if (m.MoveNext()) { Console.WriteLine(m.Current); }
5           else break;
6       }

Obviously manually write the code, too much trouble, they might also get hold of array bounds, we take a look at the c # enumerables:

 

This interface has only one method to achieve iterator, we know who realized, you can use the foreach loop, we call the iterator methods into this interface automatically call foreach

 1    public class MyEnumerable : IEnumerable<string>
 2     {
 3         public IEnumerator<string> GetEnumerator()
 4         {
 5             return new MyIEnumerator();
 6         }
 7 
 8         IEnumerator IEnumerable.GetEnumerator()
 9         {
10             return GetEnumerator();
11         }
12     }
1   MyEnumerable a = new MyEnumerable();
2    foreach (var item in a)
3    {
4        Console.WriteLine(item);
5    }

Some people may ask, and you manually change the foreach loop cycle call what’s the difference? So to speak, foreach further simplifies the call, you do not control what the end of the cycle, you do not worry about how to access the next element.

Visible call the iterator is very elegant, and if you create an iterator can be simplified, so the better, c # yield keyword is provided.

1         public IEnumerator<string> GetEnumerator()
2         {
3             yield return "

Lower horse

"; 4 yield return "

Fine horse

"; 5 yield return "

Medium horse

"; 6 }

By six lines of code, the compiler creates for us a good iterator as follows:

 1 public class MyEnumerable : IEnumerable<string>, IEnumerable
 2 {
 3     // Methods
 4     [IteratorStateMachine(typeof(d__0))]
 5     public IEnumerator<string> GetEnumerator()
 6     {
 7         yield return "

Inferior horse

"; 8 yield return "

Fine horse

"; 9 yield return "

Medium horse

"; 10 } 11 12 IEnumerator IEnumerable.GetEnumerator() 13 { 14 return this.GetEnumerator(); 15 } 16 17 // Nested Types 18 [CompilerGenerated] 19 private sealed class d__0 : IEnumerator<string>, IDisposable, IEnumerator 20 { 21 // Fields 22 private int <>1__state; 23 private string <>2__current; 24 public MyEnumerable <>4__this; 25 26 // Methods 27 [DebuggerHidden] 28 public d__0(int <>1__state) 29 { 30 this.<>1__state = <>1__state; 31 } 32 33 private bool MoveNext() 34 { 35 switch (this.<>1__state) 36 { 37 case 0: 38 this.<>1__state = -1; 39 this.<>2__current = "

Inferior horse

"; 40 this.<>1__state = 1; 41 return true; 42 43 case 1: 44 this.<>1__state = -1; 45 this.<>2__current = "

Fine horse

"; 46 this.<>1__state = 2; 47 return true; 48 49 case 2: 50 this.<>1__state = -1; 51 this.<>2__current = "

Medium horse

"; 52 this.<>1__state = 3; 53 return true; 54 55 case 3: 56 this.<>1__state = -1; 57 return false; 58 } 59 return false; 60 } 61 62 [DebuggerHidden] 63 void IEnumerator.Reset() 64 { 65 throw new NotSupportedException(); 66 } 67 68 [DebuggerHidden] 69 void IDisposable.Dispose() 70 { 71 } 72 73 // Properties 74 string IEnumerator<string>.Current 75 { 76 [DebuggerHidden] 77 get 78 { 79 return this.<>2__current; 80 } 81 } 82 83 object IEnumerator.Current 84 { 85 [DebuggerHidden] 86 get 87 { 88 return this.<>2__current; 89 } 90 } 91 } 92 }

Interestingly compiler uses the switch case realization MoveNext method, yield implement the iterator state machine.

Third, understand the yield keyword

the yield keyword, followed by the return expression or break. return expression does not end iterator, iterator only a temporary leave, under certain circumstances (when calling MoveNext method), will enter the iterator. You can understand iterator is paused or suspended state. break terminates the iterations.

Fourth, other uses iterator

Linq lazy loading expressions, if we have an array that want to filter it through Linq:

 

  List<int> ages =new List<int> { 5, 17, 30, 40 };
  var yong = ages.Where(g => g < 18);

  ages.Add(2);

   foreach (var item in yong)
   {
      Console.WriteLine(item);
   }

 

operation result:

 

Where extension method only produces an iterator, iterator told the original collection, and how to filter, to the time of the call, really filtering data, this is the Linq lazy loading principle.

 

Leave a Reply