国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

c#列舉和迭代器

2019-11-17 03:20:06
字體:
來源:轉載
供稿:網友

c#列舉和迭代器

列舉 - Enumeration

迭代器是一個值序列(集合)上的一個只讀且只向前移動的游標。迭代器要么實現了IEnumerator接口,要么實現了IEnumerator<T>接口。

從技術的角度看,如果一個對象有MoveNext方法以及Current屬性,那么我們就可以將其看作一個迭代器。

我們可以使用foreach語句去迭代一個可列舉對象。可迭代的對象其實就是一個序列的邏輯體現。可列舉的對象不但自身就是一個游標,而且它還可以生成一個游標迭代自己。因此,可列舉的對象有兩個特性

  • 實現IEnumerator接口,或實現IEnumerator<T>接口
  • 有一個方法GetEnumerator,該方法返回一個迭代器

列舉模式:

class Enumerator{    public IteratorVariableType Current {get {...}}       public bool MoveNext() {...}}class Enumerable{    public Enumerator GetEnumerator() {...}}
Enumeration pattern

為了更好的理解上面的概率和模式,我們來看下面的兩個例子

foreach (char c in "CSharp")    Console.WriteLine(c);
Sample 1
using (var enumerator = "CSharp".GetEnumerator()){    while (enumerator.MoveNext()) {        Console.WriteLine(enumerator.Current);    }}
Sample 2

Sample1采取了foreach這樣的高級方式去迭代字符串(因為字符串類實現了CharEnumerator);而Sample2則使用了底層的方式完成對字符串的迭代。 對于Sample我們使用了using語句,這是因為CharEnumerator實現了IDisposable接口,下面的代碼顯示了CharEnumrator的大部分代碼(來自微軟官方)

public sealed class CharEnumerator : IEnumerator, IDisposable{    PRivate String str;    private int index;    private char currentElement;    internal CharEnumerator(String str)    {        this.str = str;        this.index = -1;    }    public bool MoveNext()    {        if (index < (str.Length - 1))        {            index++;            currentElement = str[index];            return true;        }        else            index = str.Length;        return false;    }    public void Dispose()    {        if (str != null)            index = str.Length;        str = null;    }    public char Current    {        get        {            return currentElement;        }    }    public void Reset()    {        currentElement = (char)0;        index = -1;    }}
CharEnumerator

初始化集合

我們可使用一行語句實例一個可列舉的對象。比如:IList<Int> list = new List<int>{1,2,3};編譯時,編譯器會自動翻譯為:

IList<Int> list = new List<int>();list.Add(1);list.Add(2);list.Add(3);
Translated Code

這是因為該列舉對象實現了IEnumerable接口,而且還包含了Add方法。為了驗證此點,我們可以通過查看IL代碼的方式來確認:

IL_0000:  nop  IL_0001:  newobj     instance void class [mscorlib]System.Collections.Generic.List`1<int32>::.ctor()  IL_0006:  stloc.1  IL_0007:  ldloc.1  IL_0008:  ldc.i4.1  IL_0009:  callvirt   instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)  IL_000e:  nop  IL_000f:  ldloc.1  IL_0010:  ldc.i4.2  IL_0011:  callvirt   instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)  IL_0016:  nop  IL_0017:  ldloc.1  IL_0018:  ldc.i4.3  IL_0019:  callvirt   instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)  IL_001e:  nop  IL_001f:  ldloc.1  IL_0020:  stloc.0  IL_0021:  call       string [mscorlib]System.Console::ReadLine()
IL Code

迭代器 - Iterator

既然foreach可應用于列舉,那么一個列舉可以生成一個迭代器。很繞口很困惑是吧,我們先來看下面的例子:使用迭代器返回斐波納契數列

static IEnumerable<int> Fibonacci(int number){     for(int i=0, prevFib=1, curFib=1;i<number;i++)    {        yield return prevFib;        int newFib = prevFib + curFib;        prevFib = curFib;        curFib = newFib;    }}// teststatic void Main(string[] args){    foreach (int f in Fibonacci(10))        Console.WriteLine(f);    Console.ReadLine();}
Fibonacci

請注意,在上面的代碼中,我們使用了yield return。那么它和return有什么區別呢?return:從方法中返回一個值yield return:從當前的迭代器中生成下一個元素。yield語句每執行一次,程序的控制權就退還給調用者,而被調用者的狀態仍然保留,這就使得方法在調用者列舉下一個元素的時候能繼續執行。被調用者的狀態的生命周期取決于列舉,正因為如此,當調用者完成列舉后,被調用者的狀態得以釋放。

迭代器語法

迭代器可以是包含了一個或多個yield語句的方法、屬性、或所引器。迭代器必須返回下面四個類型之一:IEnumerable, IEnumerable<T>, IEnumerator, IEnumerator<T>

再繼續下一步之前,我們看一下IEnumerable接口和IEnumerator的定義

public interface IEnumerator{    bool MoveNext();    Object Current {get; }    void Reset();}public interface IEnumerable{      IEnumerator GetEnumerator();}
IEnumerator & IEnumerable

迭代器與列舉有不一樣的語法,在于迭代器需要返回可列舉的接口或者列舉器接口。

創建序列

迭代器可以進一步用于創建迭代。為了證實這點,我們可以擴展我們斐波納契數列例子

static IEnumerable<int> Fibonacci(int number){     for(int i=0, prevFib=1, curFib=1;i<number;i++)    {        yield return prevFib;        int newFib = prevFib + curFib;        prevFib = curFib;        curFib = newFib;    }}static IEnumerable<int> EvenNumbers(IEnumerable<int> sequence){    foreach (int x in sequence)        if (x % 2 == 0)            yield return x;}static void Main(string[] args){    foreach (int f in EvenNumbers(Fibo
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 汽车| 灌阳县| 饶阳县| 西和县| 河东区| 密云县| 海门市| 托里县| 汪清县| 利津县| 咸丰县| 彩票| 乌什县| 浮山县| 东城区| 孟连| 来凤县| 滦南县| 奎屯市| 德庆县| 竹北市| 东城区| 若尔盖县| 阿拉善右旗| 当涂县| 广丰县| 延寿县| 宜黄县| 洛阳市| 九寨沟县| 隆尧县| 五华县| 垣曲县| 邛崃市| 来宾市| 金门县| 漳平市| 无棣县| 綦江县| 区。| 区。|