157 recommendations for writing high-quality code to improve C # programs--recommendation 17: Loop traversal with foreach in most cases

Source: Internet
Author: User
Tags finally block mscorlib

Recommendation 17: Loop traversal with foreach in most cases

Since this recommendation involves the traversal of a collection, let's consider how to traverse the binding before starting this recommendation. Suppose there is an array whose traversal pattern can be traversed by the index, and if there is a Hashtable, the traversal pattern may be traversed by the key value. Regardless of which collection, if their traversal does not have a common interface, then the client, when traversing, is equivalent to encoding the specific type. In this way, our code must be modified when the requirements change. Moreover, because the client code pays too much attention to the implementation within the collection, the portability of the code becomes very poor, which directly violates the object-oriented open and closed principle. As a result, the iterator pattern is born. Now, instead of how to implement the pattern in the FCL, let's implement one of our own iterator patterns first.

 // <summary>        ///requires all iterators to implement this interface/// </summary>        InterfaceImyenumerator {BOOLMoveNext (); ObjectCurrent {Get; } }        /// <summary>        ///requires all collections to implement the interface///in this way, the client can encode the interface,///without having to focus on specific implementations/// </summary>        Interfaceimyenumerable {imyenumerator GetEnumerator (); intCount {Get; } }        classmylist:imyenumerable {Object[] items =New Object[Ten];            Imyenumerator Myenumerator;  Public Object  This[inti] {Get{returnitems[i];} Set{ This. items[i] =value;} }             Public intCount {Get{returnitems. Length; }            }             Publicimyenumerator GetEnumerator () {if(Myenumerator = =NULL) {Myenumerator=NewMyenumerator ( This); }                returnMyenumerator; }        }        classMyenumerator:imyenumerator {intindex =0;            MyList MyList;  Publicmyenumerator (MyList MyList) { This. myList =myList; }             Public BOOLMoveNext () {if(Index +1>mylist.count) {index=1; return false; }                Else{Index++; return true; }            }             Public ObjectCurrent {Get{returnMylist[index-1]; }            }        }
        Static voidMain (string[] args) {            //use interface imyenumerable instead of MyListImyenumerable list =NewMyList (); //gets the iterator that encodes the iterator in the loop instead of the collection MyListImyenumerator Enumerator =list.            GetEnumerator ();  for(inti =0; I < list. Count; i++)            {                ObjectCurrent =Enumerator.                Current; Enumerator.            MoveNext (); }             while(Enumerator. MoveNext ()) {ObjectCurrent =Enumerator.            Current; }        }

MyList simulates a collection class that inherits the interface imyenumerable, so that when the client invokes it, we can call imyenumerable directly to declare the variable, such as a statement in the code:

Imyenumerable list=new MyList ();

If we add another collection class in the future, then the encoding for list will work well even if you do not modify it. The GetEnumerator method is declared in Imyenumerable to return an object that inherits Imyenumerator. In MyList, the default return myenumerator,myenumerator is an implementation of the iterator, and if the requirements for the iteration change, you can re-develop an iterator (as shown below) and then use that iterator when the client iterates.

            //use interface imyenumerable instead of MyListImyenumerable list =NewMyList (); //gets the iterator that encodes the iterator in the loop instead of the collection MyListImyenumerator Enumerator2 = New myenumerator (list);
       //Forcall for(inti =0; I < list. Count; i++) { ObjectCurrent =Enumerator2. Current; Enumerator. MoveNext (); }
//while call         while(Enumerator. MoveNext ()) {ObjectCurrent =Enumerator2. Current; }

In the client's code, we demonstrated the For loop and the while loop during the iteration, and by that time, because of the use of iterators, two loops were not encoded for mylist, but for the iterators.

Understanding the iterator pattern that you have implemented is equivalent to understanding the corresponding pattern provided in the FCL. In the above code, the interface and type are added to the word "My", in fact, the FCL has the corresponding interface and type, but in order to demonstrate the need to add some of the content, but the general idea is the same. The client-side code is written using the corresponding type in the FCL, which should generally look like this:

 icollection<object  > List = new
     list<object  > (); IEnumerator Enumerator  = list. GetEnumerator (); 
for (int i = 0 ; I < list. Count; I++ object current = enumerator. Current; Enumerator. MoveNext ();
while (enumerator. MoveNext ()) { object current = Enumerator. Current; }

However, both the For loop and the while loop are a bit verbose, so foreach appears.

            foreach (var in list)            {                // omitted Object current = Enumerator. Current;            }

As you can see, the use of foreach simplifies the code to a minimum. It is used to traverse a collection element that inherits the IEnumerable or Ienumerable<t> interface. With IL code, we look at what's going on with foreach:

. Method Private HidebysigStaticvoidMain (string[] args)CIL managed{  . EntryPoint  //code size (0x3e)  . Maxstack  2  . Locals Init([0]class[mscorlib] System.Collections.Generic.ICollection '1<Object> List, [1]ObjectCurrent , [2]class[mscorlib] System.Collections.Generic.IEnumerator '1<Object> cs$5$0000,           [3]BOOLcs$4$0001)  il_0000:  NOP  il_0001:  newobj     instance void class[mscorlib] System.Collections.Generic.List '1<Object>::.ctor ()il_0006:  stloc.0  il_0007:  NOP  il_0008:  ldloc.0  il_0009:  callvirt   instance class[mscorlib] System.Collections.Generic.IEnumerator '1<!0>class[mscorlib] System.Collections.Generic.IEnumerable '1<Object>::getenumerator ()il_000e:  Stloc.2. try {il_000f:  BR.Sil_001ail_0011:  Ldloc.2    il_0012:  callvirt   instance!0 class[mscorlib] System.Collections.Generic.IEnumerator '1<Object>::get_current ()il_0017:  stloc.1    il_0018:  NOP    il_0019:  NOP    il_001a:  Ldloc.2    il_001b:  callvirt   instance BOOL[Mscorlib]system.collections.ienumerator::movenext ()il_0020:  stloc.3    il_0021:  Ldloc.3    il_0022:  BRTRUE.Sil_0011il_0024:  Leave. S il_0036}//end. Tryfinally {il_0026:  Ldloc.2    il_0027:  ldnull    il_0028:ceqil_002a:  stloc.3    il_002b:  Ldloc.3    il_002c:  BRTRUE.Sil_0035il_002e:  Ldloc.2    il_002f:  callvirt   instance void[mscorlib]system.idisposable::D ispose ()il_0034:  NOP    il_0035:  endfinally  }  //End Handler  il_0036:  NOP  il_0037:  Pager       Int32[Mscorlib]system.console::read ()il_003c:  Pop  il_003d:  ret} //end of Method Program::main

Viewing the IL code shows that the get_current () and MoveNext () methods are still called by the runtime.

After the MoveNext () method is called, if the result is true, jump to the beginning of the loop. In fact, the Foreach loop and the while loop are the same:

             while (Enumerator. MoveNext ())            {                object current = Enumerator. Current;            }

In addition to providing a simplified syntax, the Foreach Loop has two additional advantages:

    • Automatically place code into a try finally block
    • If the type implements the IDisposable interface, it automatically calls the Dispose method after the loop ends.

Turn from: 157 recommendations for writing high-quality code to improve C # programs Minjia

157 recommendations for writing high-quality code to improve C # programs--recommendation 17: Loop traversal with foreach in most cases

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.