欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C#中可枚舉類型詳解

 更新時(shí)間:2017年10月11日 09:02:51   作者:華然  
這篇文章主要介紹了C#中可枚舉類型,IEnumerable和IEnumerator接口j及其泛型實(shí)現(xiàn)和迭代器,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

枚舉是迭代一個(gè)集合中的數(shù)據(jù)項(xiàng)的過(guò)程。

我們經(jīng)常使用的大多數(shù)集合實(shí)際上都已經(jīng)實(shí)現(xiàn)了枚舉的接口IEnumerable和IEnumerator接口,這樣才能使用foreach迭代,有些是含有某種抽象了枚舉細(xì)節(jié)的接口:ArrayList類型有索引,BitArray有Get方法,哈希表和字典有鍵和值..........其實(shí)他們都已經(jīng)實(shí)現(xiàn)了IEnumerable和IEnumerator接口。所以一切的集合和數(shù)組都可以用IEnumerable或者IEnumerable<T>接口來(lái)定義。

 IEnumerable lists1 = new int[] { 3, 4, 5 };
      foreach(var val in lists1)
      {
        Console.WriteLine(val);
      }
      IEnumerable<int> lists2=new int[]{1,2,3};
      foreach(var val in lists2)
      {
        Console.WriteLine(val);
      }

下面講解一下 自己來(lái)定義可枚舉類型(簡(jiǎn)單說(shuō)就是自己定義的 ,可以進(jìn)行foreach迭代的集合):

因?yàn)槊杜e非常有好處,可以消除很多的錯(cuò)誤,所以實(shí)現(xiàn)某種標(biāo)準(zhǔn)是有好處的。這種標(biāo)準(zhǔn)就是IEnumerable和IEnumerator接口,必須實(shí)現(xiàn)了它才能夠使用foreach迭代,才能真正算是一個(gè)自己定義的,功能健全的集合。

我們自己建立的可枚舉類型必須實(shí)現(xiàn)IEnumerable和IEnumerator接口(其實(shí)兩者都有一個(gè)泛型實(shí)現(xiàn))。

IEnumerable接口含有一個(gè)方法,該方法返回一個(gè)枚舉器對(duì)象,枚舉器對(duì)象實(shí)現(xiàn)了IEnumerator接口(實(shí)際上可以認(rèn)為繼承和實(shí)現(xiàn)了IEnumerator的接口的類的對(duì)象就是枚舉器對(duì)象),可以用它來(lái)進(jìn)行迭代。

下面是兩個(gè)接口的定義(系統(tǒng)早已經(jīng)定義好):

 public interface IEnumerable
  {
    IEnumerator GetEnumerator();
  }

該接口只有一個(gè)GetEnumerator的方法,返回一個(gè)枚舉器,用于枚舉集合中的元素。 

 public interface IEnumerator
  {
    object Current { get; };//Current屬性返回集合的當(dāng)前元素
    bool MoveNext();    //將枚舉移動(dòng)到下一位
    void Reset();     //使枚舉回到開(kāi)頭
  }

凡是繼承和實(shí)現(xiàn)了上面這個(gè)接口的類對(duì)象就是枚舉器,可以利用上面的三個(gè)方法進(jìn)行枚舉,非常安全。不過(guò)需要自己在繼承了接口的代碼中去寫實(shí)現(xiàn)過(guò)程。

一般的情況是:枚舉器是枚舉模式的一部分,通常被實(shí)現(xiàn)為枚舉類型(繼承IEnumerable)的一個(gè)嵌套類(繼承IEnumerator)。嵌套類的好處就是可以訪問(wèn)外部類的私有成員,不破壞封裝的原則。

下面我們自己來(lái)定義一個(gè)枚舉類型,代碼如下:

public class SimpleCollection :IEnumerable
  {
    //定義一個(gè)數(shù)組的字段
    private object[] array;

    //定義一個(gè)構(gòu)造函數(shù)
    public SimpleCollection(object []items)
    {
      array = items;
    }
    //實(shí)現(xiàn)IEnumerable接口的GetNumerator方法 該方法返回一個(gè)繼承IEnumerator接口的類的實(shí)例
    public  IEnumerator GetEnumerator()
    {
      return  new Enumerator(array);
    }
    //定義一個(gè)嵌套類來(lái)繼承IEnumerator的接口
    public class Enumerator : IEnumerator
    {
      //定義一個(gè)標(biāo)記字段
      private int flag;
      //定義一個(gè)數(shù)組的字段
      private object[] elements = null;
      //定義一個(gè)構(gòu)造函數(shù)
      public Enumerator(object []items)
      {
        elements = items;
        flag = -1; //將標(biāo)記位初始化
        
        //也可以采用下面的方法
        //elements = new object[items.Length];
        //Array.Copy(items, elements, items.Length);//此靜態(tài)方法用于將一個(gè)數(shù)組中的元素復(fù)制到另外一個(gè)數(shù)組
      }
      //實(shí)現(xiàn)IEnumerator接口的Current屬性; 此屬性返回集合的當(dāng)前元素,是只讀的
      public object Current
      {
        get
        {
          if (flag > elements.Length - 1) throw new InvalidOperationException("枚舉已經(jīng)結(jié)束");
          else if (flag < 0) throw new InvalidOperationException("枚舉尚未開(kāi)始");
          else return elements[flag];
        }
      }
      //實(shí)現(xiàn)IEnumerator接口的MoveNext方法 將枚舉移動(dòng)到下一位
      public bool MoveNext()
      {
        ++flag;
        if (flag > (elements.Length - 1)) return false;
        else return true;
      }
      //實(shí)現(xiàn)IEnumerator接口的Reset方法 使枚舉回到開(kāi)頭
      public void Reset()
      {
        flag = -1;
      }
    }

下面來(lái)延時(shí)如何使用枚舉類型:

//下面來(lái)看枚舉類型的使用
      SimpleCollection collection = new SimpleCollection(new object[]{1,2,3,4,5});

      //使用方法
      //接口 變量名=繼承了該接口的類的實(shí)例
      IEnumerator enumrator = collection.GetEnumerator();

      while(enumrator.MoveNext())
      {
        
        Console.WriteLine(enumrator.Current);
      }
      Console.ReadKey();

 SimpleCollection simple = new SimpleCollection(new object[] { 1, 2, 3, 4, 5, 6 });
      IEnumerator enumerator = simple.GetEnumerator();
      while(enumerator.MoveNext())
      {
        Console.WriteLine(enumerator.Current);
      }
      //最重要的是,實(shí)現(xiàn)了那兩個(gè)接口,我們就可以對(duì)我們的集合使用foreach迭代了,看下面
      foreach(var s in simple)
      {
        Console.WriteLine(s);
      }

下面給出兩個(gè)接口的泛型實(shí)現(xiàn):

首先需要注意的是:

1.IEnumerable<T>接口繼承自IEnumerable      兩者具有相同接口,所以必須實(shí)現(xiàn)泛型和非泛型版本的GetEumerator方法

2.IEnumerator<T>接口繼承自IEnumerator和IDisposable  需要多實(shí)現(xiàn)泛型和非泛型版本的Current屬性和IDisposable接口的Dispose方法。

代碼如下:

////下面創(chuàng)建一個(gè)可枚舉的泛類型
  //首先該類型必須要繼承IEnumerable<T>接口
  //因?yàn)镮Enumerable<T>接口繼承IEnumerable接口 所以必須同時(shí)實(shí)現(xiàn)泛型和非泛型的GetEnumerator方法
  public class SimpleCollection<T> : IEnumerable<T>
  {
    private T[] array;
    public SimpleCollection(T[] items)
    {
      array = items;
     
    }
    //實(shí)現(xiàn)IEnumerable<T>接口的GetNumerator方法 該方法返回一個(gè)繼承IEnumerator接口的類的實(shí)例
    public IEnumerator<T> GetEnumerator()
    {
      return new Enumerator<T>(array);//這步需要重視
    }
    //為了避免混淆 在此顯式實(shí)現(xiàn)非泛型的接口
    IEnumerator IEnumerable.GetEnumerator()
    {
      return new Enumerator<T>(array);//這步需要重視
    }

    //定義一個(gè)嵌套類來(lái)繼承IEnumerator<T>的接口
    //IEnumerator<T>接口繼承自IDisposable和IEnumerator接口
    //該接口的唯一成員是Current屬性 但是同時(shí)也要實(shí)現(xiàn)其非泛型版本?。?!
    //另外還需要實(shí)現(xiàn)IDisposable的Dispose方法和IEnumerator的兩個(gè)方法
    public class Enumerator<_T> : IEnumerator<_T>
    {
      private int flag;
      private _T[] elements = null;
      public Enumerator(_T[] items)
      {
        elements = items;
        flag = -1;
      }
      //實(shí)現(xiàn)IEnumerator<T>接口的Current屬性; 此屬性返回集合的當(dāng)前元素,是只讀的
      public _T Current
      {
        get
        {
          if (flag > elements.Length - 1) throw new InvalidOperationException("枚舉已經(jīng)結(jié)束");
          else if (flag < 0) throw new InvalidOperationException("枚舉尚未開(kāi)始");
          else return elements[flag];
        }
      }
      //為了避免混淆  顯示實(shí)現(xiàn)IEnumerator接口的Current屬性
      object IEnumerator.Current
      {
        get { return Current; } //直接返回上面的泛型屬性 比較經(jīng)典
      }

      //實(shí)現(xiàn)IDisposable接口的Dispose方法 支持確定性垃圾回收 將枚舉數(shù)的狀態(tài)設(shè)置為after 也就是把標(biāo)記位設(shè)為最大索引+1
      public void Dispose()
      {
        flag = elements.Length + 1;
      }

      //實(shí)現(xiàn)IEnumerator接口的MoveNext方法 將枚舉移動(dòng)到下一位
      public bool MoveNext()
      {
        ++flag;
        if (flag > (elements.Length - 1)) return false;
        else return true;
      }
      //實(shí)現(xiàn)IEnumerator接口的Reset方法 使枚舉回到開(kāi)頭
      public void Reset()
      {
        flag = -1;
      }
    }

怎么使用呢:

   SimpleCollection<string> colletion = new SimpleCollection<string>(new string[] { "ranran", "Huaran" });
      IEnumerator<string> enumorator = colletion.GetEnumerator();
      while(enumorator.MoveNext())
      {
        Console.WriteLine(enumorator.Current);
      }
      foreach(var v in colletion)
      {
        Console.WriteLine(v);
      }
      Console.ReadKey();

還可以直接使用迭代器:
使用迭代器是另一種完全實(shí)現(xiàn)上面兩個(gè)接口的方案,這是最為簡(jiǎn)便和可讀的方法

而且使用迭代器可以很方便和快捷的設(shè)置各種枚舉情況 如雙重的迭代 反向的迭代 臨時(shí)的集合和負(fù)責(zé)迭代等等 比上面的實(shí)現(xiàn)更為簡(jiǎn)單

迭代的關(guān)鍵字是yield 需要依靠一個(gè)迭代器塊(注意是循環(huán)+yield  return,或者 yiled break)

 public class MyCollection:IEnumerable
  {
    private object[] array;
    public MyCollection(object []items)
    {
      array = items;
    }
    public IEnumerator GetEnumerator() //實(shí)現(xiàn)都可以依靠編譯器去完成
    {
      //foreach (object v in array)
      //{
      //  yield return v;
      //}

      //關(guān)鍵字是yield 并不是foreach 我們也可以按照下面這個(gè)方法進(jìn)行實(shí)現(xiàn)
      for(int i=0;i<array.Length;i++)
      {
        yield return array[i];
      }
      //當(dāng)然其它的while循環(huán)也可以。。
    }
  }
//實(shí)現(xiàn):
MyCollection collection = new MyCollection(new object[] { 1, 2, 3 });
      foreach(var v in collection)
      {
        Console.WriteLine(v);
      }

可以自己設(shè)置迭代的情況:

   public class MyCollection2:IEnumerable
  {
     private object[] array;
     public MyCollection2(object []items)
    {
      array = items;
    }
    //可以在迭代器塊中設(shè)置迭代的實(shí)現(xiàn)情況 即具體迭代多少個(gè)元素
    //比如我們只想迭代4個(gè)元素
    public IEnumerator GetEnumerator()
     {
       int count = 0;//設(shè)計(jì)一個(gè)標(biāo)記位
      foreach(object item in array)
      {
        ++count;
        yield return item;
        if (count == 4) yield break; //break關(guān)鍵字 退出迭代 實(shí)際上迭代在實(shí)現(xiàn)當(dāng)中就是一個(gè)循環(huán) 利用break跳出也合情合理
      }
     }
   
  }


//////
 MyCollection2 collection2 = new MyCollection2(new object[]{4,5,6,7,8});
      //它就只會(huì)輸出4,5,6,7
      foreach (var v in collection2)
      {
        Console.WriteLine(v);
      }

雙重迭代:

 /// <summary>
  /// 下面演示雙重迭代 即一次可以迭代兩個(gè)集合中的元素
  /// </summary>
  public class MyColletion3:IEnumerable
  {
    private object[] List1;
    public string[] List2;
    public MyColletion3(object []items1,string []items2)
    {
      this.List1 = items1;
      this.List2 = items2;
    }
    //下面進(jìn)行雙重迭代
    public IEnumerator GetEnumerator()
    {
      //關(guān)鍵代碼
      for(int index=0;index<(List1.Length>List2.Length?List2.Length:List1.Length);index++)
      {
        yield return List1[index];
        yield return List2[index];
      }
    }
  }
////////
 MyColletion3 collection3 = new MyColletion3(new object[] { 1, 2, 3, 5.5 }, new string[] { "RanRan", "Chengdu", "四川" });
      foreach(var v in collection3)
      {
        Console.WriteLine(v);
      }
      //迭代結(jié)果是1 RanRan 2 Chengdu 3 四川

反向迭代:依靠Reverse屬性

  /// <summary>
  /// 下面演示反向迭代 說(shuō)白了就是迭代是從后面開(kāi)始的 反向迭代器是在Reverse屬性當(dāng)中實(shí)現(xiàn)的
  /// </summary>
  public class MyColletion4:IEnumerable
  {
    private object[] items;
    public MyColletion4(object []temps)
    {
      this.items = temps;
    }
    //一般的正向迭代
    public IEnumerator GetEnumerator()
    {
      for(int index=0;index<items.Length;index++)
      {
        yield return items[index];
      }
    }
    //實(shí)現(xiàn)反向迭代
    public IEnumerable Reverse //注意返回IEnumerable對(duì)象
    {
      get
      {
        for (int index = items.Length - 1; index > -1; index--)
        {
          yield return items[index];
        }
      }
    }
  }
////
 MyColletion4 collection4 = new MyColletion4(new object[] { 1, 2, 3, 4 });
      foreach (var v in collection4)
      {
        Console.WriteLine(v);
      }
      //反向迭代
      foreach(var v in collection4.Reverse)
      {
        Console.WriteLine(v);
      }
      //迭代結(jié)果是 4 3 2 1

當(dāng)然也有一個(gè)臨時(shí)集合,順便補(bǔ)充一下,迭代和枚舉實(shí)現(xiàn)的方案很多,一個(gè)返回IEnumerable的方法中加上迭代器塊也是一個(gè)迭代集合

具體看下面的代碼

 //還有一種最為簡(jiǎn)單的迭代 就是一個(gè)返回IEnumerable對(duì)象的方法 在這方法中寫上迭代器
    //在此補(bǔ)充一個(gè)臨時(shí)集合 關(guān)鍵看代碼怎么寫(以枚舉當(dāng)前月份的日期為列子)
    public static IEnumerable GetMonthDate()
    {
      DateTime dt = DateTime.Now;
      int currentMonth = dt.Month;
      while(currentMonth==dt.Month)
      {
        string temp = currentMonth.ToString() + "/" + dt.Day.ToString();
        dt = dt.AddDays(1);
        yield return temp;
      }
    }

///實(shí)現(xiàn)
foreach(var v in GetMonthDate())
      {
        Console.WriteLine(v);
      }

這兒 我作為一個(gè)新手自己給自己總結(jié)一下可枚舉類型和接口的含義:

可枚舉類型(集合&數(shù)組等):

              在實(shí)際開(kāi)發(fā)當(dāng)中,可以自己去定義一些與集合差不多的類型,對(duì)該類型的元素的訪問(wèn),用一般的while,for循環(huán)比較不方便,我們需要自己去定義一個(gè)枚舉器。

              枚舉類型(繼承IEnumerable接口):包括一個(gè)集合元素和一個(gè)枚舉器。

              枚舉器是枚舉類型當(dāng)中的一個(gè)嵌套類(繼承了IEnumerator接口):具體實(shí)現(xiàn)見(jiàn)上。

              /////// 這樣便可以讓自定義的可枚舉類型實(shí)現(xiàn)foreach迭代。

              當(dāng)然也可以直接利用迭代來(lái)實(shí)現(xiàn)上面兩個(gè)接口。//////

接口:是一種標(biāo)準(zhǔn),它給出了一種約束和引導(dǎo),需要我們?nèi)懘a實(shí)現(xiàn)它。雖然看上去多次一舉,不過(guò)在后面對(duì)類的實(shí)例的使用中非常方便。

 以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • C# MemoryStream類案例詳解

    C# MemoryStream類案例詳解

    這篇文章主要介紹了C# MemoryStream類案例詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • C#使用Stack<T>進(jìn)行堆棧設(shè)計(jì)的實(shí)現(xiàn)

    C#使用Stack<T>進(jìn)行堆棧設(shè)計(jì)的實(shí)現(xiàn)

    堆棧代表了一個(gè)后進(jìn)先出的對(duì)象集合,當(dāng)您需要對(duì)各項(xiàng)進(jìn)行后進(jìn)先出的訪問(wèn)時(shí),則使用堆棧,本文主要介紹了C#使用Stack<T>類進(jìn)行堆棧設(shè)計(jì)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),感興趣的可以了解一下
    2024-03-03
  • 聊一聊C# 8.0中的await foreach使用

    聊一聊C# 8.0中的await foreach使用

    這篇文章主要介紹了聊一聊C# 8.0中的await foreach使用,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-06-06
  • C#中利用Lotus notes公共郵箱發(fā)送郵件的方法

    C#中利用Lotus notes公共郵箱發(fā)送郵件的方法

    這篇文章主要給大家介紹了關(guān)于C#中利用Lotus notes公共郵箱發(fā)送郵件的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧。
    2018-02-02
  • C#實(shí)現(xiàn)自定義單選和復(fù)選按鈕樣式

    C#實(shí)現(xiàn)自定義單選和復(fù)選按鈕樣式

    這篇文章主要為大家詳細(xì)介紹了如何利用C#實(shí)現(xiàn)定義單選和復(fù)選按鈕樣式,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C#有一定的幫助,感興趣的小伙伴可以跟隨小編一起了解一下
    2022-12-12
  • c# 備忘錄模式

    c# 備忘錄模式

    備忘錄模式:在不破壞封裝的前提下,捕獲一個(gè)對(duì)象的內(nèi)部狀態(tài),并在這個(gè)對(duì)象之外的地方保存這個(gè)狀態(tài),這樣以后就可將該對(duì)象恢復(fù)到原來(lái)保存的狀態(tài)了
    2012-10-10
  • C# 使用GDI繪制雷達(dá)圖的實(shí)例

    C# 使用GDI繪制雷達(dá)圖的實(shí)例

    這篇文章主要介紹了C# 使用GDI繪制雷達(dá)圖,本文通過(guò)一段實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-11-11
  • C#中事件只能在內(nèi)部調(diào)用的原因分析

    C#中事件只能在內(nèi)部調(diào)用的原因分析

    事件(Event)?基本上說(shuō)是一個(gè)用戶操作,如按鍵、點(diǎn)擊、鼠標(biāo)移動(dòng)等等,或者是一些提示信息,如系統(tǒng)生成的通知。應(yīng)用程序需要在事件發(fā)生時(shí)響應(yīng)事件,這篇文章主要介紹了C#中事件為什么只能在內(nèi)部調(diào)用,需要的朋友可以參考下
    2021-11-11
  • C# 中 System.Index 結(jié)構(gòu)體和 Hat 運(yùn)算符(^)的使用示例

    C# 中 System.Index 結(jié)構(gòu)體和 Hat 運(yùn)算符(^)的使用示例

    這篇文章主要介紹了C# 中 System.Index 結(jié)構(gòu)體和 Hat 運(yùn)算符(^)的使用示例,幫助大家更好的理解和使用C#,感興趣的朋友可以了解下
    2020-09-09
  • C#中LINQ的Select與SelectMany函數(shù)使用

    C#中LINQ的Select與SelectMany函數(shù)使用

    這篇文章主要介紹了C#中LINQ的Select與SelectMany函數(shù)使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-08-08

最新評(píng)論