小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

IEnumerable和IEnumerator介紹和區(qū)別

 zww_blog 2014-02-24
csdn上看到一篇有關(guān)IEnumerable和IEnumerator 的文章個人感覺不錯,粘過來跟大家分享一下:
初學(xué)C#的時候,老是被IEnumerable、IEnumerator、ICollection等這樣的接口弄的糊里糊涂,我覺得有必要切底的弄清楚IEnumerable和IEnumerator的本質(zhì)。

下面我們先看IEnumerable和IEnumerator兩個接口的語法定義。其實IEnumerable接口是非常的簡單,只包含一個抽象的方法GetEnumerator(),它返回一個可用于循環(huán)訪問集合的IEnumerator對象。IEnumerator對象有什么呢?它是一個真正的集合訪問器,沒有它,就不能使用foreach語句遍歷集合或數(shù)組,因為只有IEnumerator對象才能訪問集合中的項,假如連集合中的項都訪問不了,那么進行集合的循環(huán)遍歷是不可能的事情了。那么讓我們看看IEnumerator接口有定義了什么東西??聪聢D我們知道IEnumerator接口定義了一個Current屬性,MoveNext和Reset兩個方法,這是多么的簡約。既然IEnumerator對象時一個訪問器,那至少應(yīng)該有一個Current屬性,來獲取當(dāng)前集合中的項吧。

MoveNext方法只是將游標(biāo)的內(nèi)部位置向前移動(就是移到一下個元素而已),要想進行循環(huán)遍歷,不向前移動一下怎么行呢?

詳細講解:

說到IEnumerable總是會和IEnumerator、foreach聯(lián)系在一起。

C# 支持關(guān)鍵字foreach,允許我們遍歷任何數(shù)組類型的內(nèi)容:

//遍歷數(shù)組的項

int[] myArrayOfInts = {10,20,30,40};

foreach(int i in my myArrayOfInts)

{

    Console.WirteLine(i);

}

雖然看上去只有數(shù)組才可以使用這個結(jié)構(gòu),其實任何支持GetEnumerator()方法的類型都可以通過foreach結(jié)構(gòu)進行運算。

[csharp] view plaincopy
  1. public class Garage  
  2. {  
  3.     Car[] carArray = new Car[4];  //在Garage中定義一個Car類型的數(shù)組carArray,其實carArray在這里的本質(zhì)是一個數(shù)組字段  
  4.   
  5.     //啟動時填充一些Car對象  
  6.     public Garage()  
  7.     {  
  8.         //為數(shù)組字段賦值  
  9.         carArray[0] = new Car("Rusty", 30);  
  10.         carArray[1] = new Car("Clunker", 50);  
  11.         carArray[2] = new Car("Zippy", 30);  
  12.         carArray[3] = new Car("Fred", 45);  
  13.     }  
  14. }  

理想情況下,與數(shù)據(jù)值數(shù)組一樣,使用foreach構(gòu)造迭代Garage對象中的每一個子項比較方便:

[csharp] view plaincopy
  1. //這看起來好像是可行的  
  2. lass Program  
  3.    {  
  4.        static void Main(string[] args)  
  5.        {  
  6.            Console.WriteLine("*********Fun with IEnumberable/IEnumerator************\n");  
  7.            Garage carLot = new Garage();  
  8.   
  9.            //交出集合中的每一Car對象嗎  
  10.             foreach (Car c in carLot)  
  11.            {  
  12.                Console.WriteLine("{0} is going {1} MPH", c.CarName, c.CurrentSpeed);  
  13.            }  
  14.   
  15.            Console.ReadLine();  
  16.        }  
  17.    }  

讓人沮喪的是,編譯器通知我們Garage類沒有實現(xiàn)名為GetEnumerator()的方法(顯然用foreach遍歷Garage對象是不可能的事情,因為Garage類沒有實現(xiàn)GetEnumerator()方法,Garage對象就不可能返回一個IEnumerator對象,沒有IEnumerator對象,就不可能調(diào)用方法MoveNext(),調(diào)用不了MoveNext,就不可能循環(huán)的了)。這個方法是有隱藏在System.collections命名空間中的IEnumerable接口定義的。(特別注意,其實我們循環(huán)遍歷的都是對象而不是類,只是這個對象是一個集合對象

支持這種行為的類或結(jié)構(gòu)實際上是宣告它們向調(diào)用者公開所包含的子項:

//這個接口告知調(diào)方對象的子項可以枚舉

public interface IEnumerable

{

    IEnumerator GetEnumerator();

}

可以看到,GetEnumerator方法返回對另一個接口System.Collections.IEnumerator的引用。這個接口提供了基礎(chǔ)設(shè)施,調(diào)用方可以用來移動IEnumerable兼容容器包含的內(nèi)部對象。

//這個接口允許調(diào)用方獲取一個容器的子項

public interface IEnumerator

{

    bool MoveNext();             //將游標(biāo)的內(nèi)部位置向前移動

    object Current{get;}       //獲取當(dāng)前的項(只讀屬性)

    void Reset();                 //將游標(biāo)重置到第一個成員前面

}

所以,要想Garage類也可以使用foreach遍歷其中的項,那我們就要修改Garage類型使之支持這些接口,可以手工實現(xiàn)每一個方法,不過這得花費不少功夫。雖然自己開發(fā)GetEnumerator()、MoveNext()、Current和Reset()也沒有問題,但有一個更簡單的辦法。因為System.Array類型和其他許多類型(如List)已經(jīng)實現(xiàn)了IEnumerable和IEnumerator接口,你可以簡單委托請求到System.Array,如下所示:

[csharp] view plaincopy
  1. namespace MyCarIEnumerator  
  2. {  
  3.     public class Garage:IEnumerable  
  4.     {  
  5.         Car[] carArray = new Car[4];  
  6.   
  7.         //啟動時填充一些Car對象  
  8.         public Garage()  
  9.         {  
  10.             carArray[0] = new Car("Rusty", 30);  
  11.             carArray[1] = new Car("Clunker", 50);  
  12.             carArray[2] = new Car("Zippy", 30);  
  13.             carArray[3] = new Car("Fred", 45);  
  14.         }  
  15.         public IEnumerator GetEnumerator()  
  16.         {  
  17.             return this.carArray.GetEnumerator();  
  18.         }  
  19.     }  
  20. }  
  21. //修改Garage類型之后,就可以在C#foreach結(jié)構(gòu)中安全使用該類型了。  
[csharp] view plaincopy
  1. //除此之外,GetEnumerator()被定義為公開的,對象用戶可以與IEnumerator類型交互:   
  2. namespace MyCarIEnumerator  
  3. {  
  4.     class Program  
  5.     {  
  6.         static void Main(string[] args)  
  7.         {  
  8.             Console.WriteLine("*********Fun with IEnumberable/IEnumerator************\n");  
  9.             Garage carLot = new Garage();  
  10.   
  11.             //交出集合中的每一Car對象嗎  
  12.             foreach (Car c in carLot)  //之所以遍歷carLot,是因為carLot.GetEnumerator()返回的項時Car類型,這個十分重要  
  13.             {  
  14.                 Console.WriteLine("{0} is going {1} MPH", c.CarName, c.CurrentSpeed);  
  15.             }  
  16.   
  17.             Console.WriteLine("GetEnumerator被定義為公開的,對象用戶可以與IEnumerator類型交互,下面的結(jié)果與上面是一致的");  
  18.             //手動與IEnumerator協(xié)作  
  19.             IEnumerator i = carLot.GetEnumerator();  
  20.             while (i.MoveNext())  
  21.             {   
  22.                 Car myCar = (Car)i.Current;  
  23.                 Console.WriteLine("{0} is going {1} MPH", myCar.CarName, myCar.CurrentSpeed);  
  24.             }  
  25.             Console.ReadLine();  
  26.         }  
  27.     }  
  28. }  

 

下面我們來看看手工實現(xiàn)IEnumberable接口和IEnumerator接口中的方法:

[csharp] view plaincopy
  1. namespace ForeachTestCase  
  2. {  
  3.       //繼承IEnumerable接口,其實也可以不繼承這個接口,只要類里面含有返回IEnumberator引用的GetEnumerator()方法即可  
  4.     class ForeachTest:IEnumerable     {  
  5.         private string[] elements;  //裝載字符串的數(shù)組  
  6.         private int ctr = 0;  //數(shù)組的下標(biāo)計數(shù)器  
  7.   
  8.         /// <summary>  
  9.         /// 初始化的字符串  
  10.         /// </summary>  
  11.         /// <param name="initialStrings"></param>  
  12.         ForeachTest(params string[] initialStrings)  
  13.         {   
  14.             //為字符串分配內(nèi)存空間  
  15.             elements = new String[8];  
  16.             //復(fù)制傳遞給構(gòu)造方法的字符串  
  17.             foreach (string s in initialStrings)  
  18.             {  
  19.                 elements[ctr++] = s;   
  20.             }  
  21.         }  
  22.   
  23.         /// <summary>  
  24.         ///  構(gòu)造函數(shù)  
  25.         /// </summary>  
  26.         /// <param name="source">初始化的字符串</param>  
  27.         /// <param name="delimiters">分隔符,可以是一個或多個字符分隔</param>  
  28.         ForeachTest(string initialStrings, char[] delimiters)   
  29.         {  
  30.             elements = initialStrings.Split(delimiters);  
  31.         }  
  32.   
  33.         //實現(xiàn)接口中得方法  
  34.         public IEnumerator GetEnumerator()  
  35.         {  
  36.             return  new ForeachTestEnumerator(this);  
  37.         }  
  38.   
  39.         private class ForeachTestEnumerator : IEnumerator  
  40.         {  
  41.             private int position = -1;  
  42.             private ForeachTest t;  
  43.             public ForeachTestEnumerator(ForeachTest t)  
  44.             {  
  45.                 this.t = t;  
  46.             }  
  47.  
  48.             #region 實現(xiàn)接口  
  49.   
  50.             public object Current  
  51.             {  
  52.                 get  
  53.                 {  
  54.                     return t.elements[position];  
  55.                 }  
  56.             }  
  57.   
  58.             public bool MoveNext()  
  59.             {  
  60.                 if (position < t.elements.Length - 1)  
  61.                 {  
  62.                     position++;  
  63.                     return true;  
  64.                 }  
  65.                 else  
  66.                 {  
  67.                     return false;  
  68.                 }  
  69.             }  
  70.   
  71.             public void Reset()  
  72.             {  
  73.                 position = -1;  
  74.             }  
  75.  
  76.             #endregion  
  77.         }  
  78.         static void Main(string[] args)  
  79.         {  
  80.             // ForeachTest f = new ForeachTest("This is a sample sentence.", new char[] { ' ', '-' });  
  81.             ForeachTest f = new ForeachTest("This""is""a""sample""sentence.");  
  82.             foreach (string item in f)  
  83.             {  
  84.                 System.Console.WriteLine(item);  
  85.             }  
  86.             Console.ReadKey();  
  87.         }  
  88.     }  
  89. }  

 

IEnumerable<T>接口

實現(xiàn)了IEnmerable<T>接口的集合,是強類型的。它為子對象的迭代提供類型更加安全的方式。

[csharp] view plaincopy
  1. public  class ListBoxTest:IEnumerable<String>  
  2.    {  
  3.        private string[] strings;  
  4.        private int ctr = 0;  
  5.       
  6.        #region IEnumerable<string> 成員  
  7.        //可枚舉的類可以返回枚舉  
  8.        public IEnumerator<string> GetEnumerator()  
  9.        {  
  10.            foreach (string s in strings)  
  11.            {  
  12.                yield return s;  
  13.            }  
  14.        }  
  15.  
  16.        #endregion  
  17.  
  18.        #region IEnumerable 成員  
  19.        //顯式實現(xiàn)接口  
  20.        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()  
  21.        {  
  22.            return GetEnumerator();  
  23.        }  
  24.  
  25.        #endregion  
  26.   
  27.        //用字符串初始化列表框  
  28.        public ListBoxTest(params string[] initialStrings)  
  29.        {   
  30.            //為字符串分配內(nèi)存空間  
  31.            strings = new String[8];  
  32.            //復(fù)制傳遞給構(gòu)造方法的字符串  
  33.            foreach (string s in initialStrings)  
  34.            {  
  35.                strings[ctr++] = s;   
  36.            }  
  37.        }  
  38.   
  39.        //在列表框最后添加一個字符串  
  40.        public void Add(string theString)  
  41.        {   
  42.            strings[ctr] = theString;  
  43.            ctr++;  
  44.        }  
  45.   
  46.        //允許數(shù)組式的訪問  
  47.        public string this[int index]  
  48.        {  
  49.            get {  
  50.                if (index < 0 || index >= strings.Length)  
  51.                {   
  52.                    //處理不良索引  
  53.                }  
  54.                return strings[index];  
  55.            }  
  56.            set {   
  57.                strings[index] = value;  
  58.            }  
  59.        }  
  60.   
  61.        //發(fā)布擁有的字符串?dāng)?shù)  
  62.        public int GetNumEntries()  
  63.        {  
  64.            return ctr;  
  65.        }  
  66.    }  
[csharp] view plaincopy
  1. class Program  
  2.   {  
  3.       static void Main(string[] args)  
  4.       {  
  5.           //創(chuàng)建一個新的列表框并初始化  
  6.           ListBoxTest lbt = new ListBoxTest("Hello""World");  
  7.   
  8.           //添加新的字符串  
  9.           lbt.Add("Who");  
  10.           lbt.Add("Is");  
  11.           lbt.Add("Douglas");  
  12.           lbt.Add("Adams");  
  13.   
  14.           //測試訪問  
  15.           string subst = "Universe";  
  16.           lbt[1] = subst;  
  17.   
  18.           //訪問所有的字符串  
  19.           foreach (string s in lbt)  
  20.           {  
  21.               Console.WriteLine("Value:{0}", s);  
  22.           }  
  23.           Console.ReadKey();  
  24.       }  
  25.   }  


 綜上所述,一個類型是否支持foreach遍歷,必須滿足下面條件:

方案1:讓這個類實現(xiàn)IEnumerable接口

方案2:這個類有一個public的GetEnumerator的實例方法,并且返回類型中有public 的bool MoveNext()實例方法和public的Current實例屬性。

C# IEnumerable和IEnumerator的區(qū)別,如何實現(xiàn)

IEnumerable接口和IEnumerator接口是.NET中非常重要的接口,二者有何區(qū)別?

    1. 簡單來說IEnumerable是一個聲明式的接口,聲明實現(xiàn)該接口的類就是“可迭代的enumerable”,但并沒用說明如何實現(xiàn)迭代器(iterator).其代碼實現(xiàn)為:

         public interface IEnumerable
         {
                IEnumerator GetEnumerator();
          }
    2. 而IEnumerator接口是實現(xiàn)式接口,它聲明實現(xiàn)該接口的類就可以作為一個迭代器iterator.其代碼實現(xiàn)為:

        public interface IEnumerator
       {
                object Current { get; }

                bool MoveNext();
                void Reset();
        }

   3.一個collection要支持Foreach進行遍歷,就必須實現(xiàn)IEnumerable,并一某種方式返回迭代器對象:IEnumerator.

   那么又如何實現(xiàn)這兩個接口呢? 其代碼如下:

  假設(shè)有一個Person類,其有兩個屬性FirstName和LastName

  public class Person
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public Person(string firstName, string lastName)
        {
            this.FirstName = firstName;
            this.LastName = lastName;
        }
    }

另外通過People類來實現(xiàn)IEnumerable和IEnumerator接口.

//實現(xiàn)IEnumerable接口

public class People :IEnumerable

{

   public Person [] pers;

   public People(Person [] ps)

    {

      this.pers = ps;

    }

    public IEnumerator GetEnumerator()

    {

         //foreach(Person p in pers)

         // {

             //  yield return p;

          // }

      return new People1(pers);

      }

}

  //實現(xiàn)IEnumerator接口

   public class People1 : IEnumerator
    {
        public Person[] pers;
        public People1(Person[] per)
        {
            this.pers = per;
        }
        int position = -1;

        public bool MoveNext()
        {
            position++;
            return position < pers.Length;
        }
        public void Reset()
        {
            position=-1;
        }
        public object Current
        {
            get
            {
               try
               {
                   return pers[position];
               }
                catch(IndexOutOfRangeException ex)
                {
                    throw new InvalidOperationException();
                }
            }
        }
    }

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多