国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
C# 中的枚舉器

C# 中的枚舉器

出處:http://www.ondotnet.com/pub/a/dotnet/2004/06/07/liberty.html

術(shù)語表

Iterator:枚舉器

如果你正在創(chuàng)建一個(gè)表現(xiàn)和行為都類似于集合的類,允許類的用戶使用foreach語句對(duì)集合中的成員進(jìn)行枚舉將會(huì)是很方便的。這在C# 2.0中比 C# 1.1更容易實(shí)現(xiàn)一些。作為演示,我們先在 C# 1.1中為一個(gè)簡單的集合添加枚舉,然后我們修改這個(gè)范例,使用新的C#2.0 枚舉構(gòu)建方法。

我們將以創(chuàng)建一個(gè)簡單化的List Box作為開始,它將包含一個(gè)8字符串的數(shù)組和一個(gè)整型,這個(gè)整型用于記錄數(shù)組中已經(jīng)添加了多少字符串。構(gòu)造函數(shù)將對(duì)數(shù)組進(jìn)行初始化并使用傳遞進(jìn)來的參數(shù)填充它。

public ListBox(params string[] initialStrings)
{
    strings = new String[8];

    foreach (string s in initialStrings)
    {
       strings[ctr++] = s;
    }
}

除此以外,ListBox類還需要一個(gè)Add方法(進(jìn)行添加 string 的操作) 和 一個(gè)返回?cái)?shù)組中字符串個(gè)數(shù)的方法。

public void Add(string theString)
{
    strings[ctr] = theString;
    ctr++;
}

public int GetNumEntries()
{
    return ctr;
}

 

NOTE:實(shí)際開發(fā)中,通常使用ArrayList,而不是固定大小的數(shù)組。在這里為了程序簡單就沒有做數(shù)組下標(biāo)越界的檢測。

從感覺上看,ListBox像是一個(gè)集合,如果可以使用集合中通常使用的 foreach 循環(huán)來獲取listBox中的所有字符串將會(huì)是非常便利的。如此的話,可以這樣書寫代碼:

ListBox lb = new ListBox("a", "b", "c", "d", "e", "f", "g", "h");
foreach (string s in lb) {
    Console.WriteLine(s);
}

但是,會(huì)得到這樣一個(gè)錯(cuò)誤:

“Iterator.ListBox”不包含“GetEnumerator”的公共定義,因此 foreach 語句不能作用于“Iterator.ListBox”類型的變量

想要使用foreach語句,還必須實(shí)現(xiàn)IEnumerable 接口。

這個(gè)接口只要求實(shí)現(xiàn)一個(gè)方法: GetEnumerator。這個(gè)方法必須返回一個(gè)實(shí)現(xiàn)了IEnumerator 接口的對(duì)象。除此以外,我們需要返回的這個(gè)對(duì)象不僅實(shí)現(xiàn)了IEnumerator,而且知道如何枚舉ListBox對(duì)象。你將需要?jiǎng)?chuàng)建一個(gè) ListBoxEmunerator(在下面描述):

NOTE: IEnumerable 和 IEnumerator 是不同的接口,請(qǐng)不要搞混了。

 

public IEnumerator GetEnumerator()
{
    return new ListBoxEnumerator();
}

現(xiàn)在,ListBox 可以使用 foreach 循環(huán)了:

ListBox lbt = new ListBox("Hello", "World");

lbt.Add("Who");
lbt.Add("Is");
lbt.Add("John");
lbt.Add("Galt");

foreach (string s in lbt)
{
    Console.WriteLine("Value: {0}", s);
}

先是實(shí)例化這個(gè)ListBox ,并初始了兩個(gè)字符串,隨后又添加了四個(gè)。foreach循環(huán)接受ListBox實(shí)例,并且迭代它,依次返回字符串。輸出是:

Hello
World
Who
Is
John
Galt

實(shí)現(xiàn) IEnumerator 接口

注意到ListBoxEnumerator不僅需要實(shí)現(xiàn)IEnumerator接口,對(duì)于ListBox類它也需要一些特別了解;特別是,它必須可以獲得ListBox的字符串?dāng)?shù)組并且遍歷其所包含的字符串。IEnumerable 類和與其相關(guān)的 IEnumerator類之間的關(guān)系有一點(diǎn)微妙。實(shí)現(xiàn)IEnumerator接口的最好辦法是在IEnumerable類里創(chuàng)建一個(gè)嵌套的IEnumerator類。

public class ListBox : IEnumerable
{
    // 嵌套的私有ListBoxEnumerator類實(shí)現(xiàn)
    private class ListBoxEnumerator : IEnumerator
    {
       // 代碼實(shí)現(xiàn)...
    }
    // ListBox類的代碼...
}

注意ListBoxEnumerator需要對(duì)它所嵌入的ListBox類的一個(gè)引用。你可以通過ListBoxEnumerator的構(gòu)造函數(shù)來傳遞。

為了實(shí)現(xiàn)IEnumerator接口,ListBoxEnumerator需要兩個(gè)方法:MoveNext和Reset,還有一個(gè)屬性:Current。這些方法和屬性的任務(wù)是創(chuàng)建一個(gè)狀態(tài)機(jī)制,確保你可以在任何時(shí)候得知ListBox中的哪個(gè)元素是當(dāng)前元素,并獲得那個(gè)元素。

在這個(gè)例子中,這種狀態(tài)機(jī)制是通過維護(hù)一個(gè)標(biāo)明當(dāng)前string的索引值來完成的,并且,你可以通過對(duì)外部類的string集合進(jìn)行索引來返回這個(gè)當(dāng)前的string。為了達(dá)到這個(gè)目標(biāo),你需要一個(gè)成員變量保存對(duì)于外部ListBox對(duì)象的引用,以及一個(gè)整型用于保存當(dāng)前索引。

private ListBox lbt;
private int index;

每次Reset方法被調(diào)用的時(shí)候,index被置為 -1。

public void Reset()
{
    index = -1;
}

每次MoveNext被調(diào)用的時(shí)候,外部類的數(shù)組檢查時(shí)候已經(jīng)到了末尾,如果是這樣,方法返回false。如果集合中還有對(duì)象,index將增加,并且方法返回true。

public bool MoveNext()
{
    index++;
    if (index >= lbt.strings.Length)
    {
       return false;
    }else
    {
       return true;
    }
}

最后,如果MoveNext方法返回True,foreach循環(huán)將調(diào)用Current屬性。ListBoxEnumerator的Current屬性的實(shí)現(xiàn)是索引外部類(ListBox)中的集合,并且返回找到的對(duì)象(這個(gè)例子中,是一個(gè)字符串)。注意,返回一個(gè)Object是因?yàn)镮Enumerator接口中Current屬性的簽名如此。

public object Current
{
    get {
       return(lbt[index]);
    }
}

在1.1中,所有想要通過foreach循環(huán)來迭代的類都需要實(shí)現(xiàn)IEnumerable接口,于是,必須創(chuàng)建一個(gè)實(shí)現(xiàn)了IEnumerator的類。最糟的是,enumerator返回的值并不是類型安全的。記得Current屬性返回一個(gè)Object對(duì)象;它僅僅簡單的假設(shè)你所返回的值與foreach循環(huán)所期望的相符合。

C# 2.0 的解救辦法

使用C# 2.0 這些問題如同五月末的雪般融化了。在這個(gè)例子的2.0版本中,我重寫上面的列表,使用C# 2.0的兩個(gè)新特性:泛型 和 枚舉器。

我以重新定義實(shí)現(xiàn)IEumerable<string>的ListBox作為開始:

public class ListBox : IEnumerable<string>

這樣做確定這個(gè)類可以在foreach循環(huán)中使用,同時(shí)確保迭代的值是string類型。

現(xiàn)在,從上個(gè)例子中挪去整個(gè)嵌套類,并且用下面的代碼替換 GetEnumerator方法。

public IEnumerator<string> GetEnumerator()
{
   foreach (string s in strings)
   {
      yield return s;
   }
}

GetEnumerator方法使用了新的 yield 語句。yield語句返回一個(gè)表達(dá)式。yield語句僅在迭代塊中出現(xiàn),并且返回foreach語句所期望的值。那也就是,對(duì)GetEnumerator的每次調(diào)用都將會(huì)產(chǎn)生集合中的下一個(gè)字符串;所有的狀態(tài)管理已經(jīng)都為你做好了!

就這樣了,你已經(jīng)完成了。不需要為每個(gè)類型實(shí)現(xiàn)你自己的enumerator,不需要?jiǎng)?chuàng)建嵌套類。你已經(jīng)移除了至少30行代碼,并且極大地簡化了你的代碼。程序繼續(xù)像期望的那樣運(yùn)行,但是狀態(tài)管理不再是你的任務(wù),所有的都為你做好了。更進(jìn)一步,由枚舉器所返回的值一定是string類型,如果你想要返回其他類型,你可以修改IEnumerable泛型語句,IEnumerable泛型語句將反射新類型。

關(guān)于Yield的更多內(nèi)容

作為對(duì)上一節(jié)的一些說明,應(yīng)該告訴你:實(shí)際上,你可以在yield語句塊中yield一個(gè)以上的值。這樣,下面的語句是完全正確的C#語句:

public IEnumerator GetEnumerator()
{
   yield return "Who";
   yield return " is";
   yield return "John Galt?";
}

假設(shè)上面的代碼位于一個(gè)名為foo的類中,你可以這樣寫:

foreach ( string s in new foo())
{
   Console.Write(s);
}

輸出結(jié)果將會(huì)是:

Who is John Galt?

如果你現(xiàn)在停下來思考一下,這些也是之前的代碼所做的事。它遍歷了自己的foreach循環(huán),并且產(chǎn)生出它所找到的每個(gè)string字符串。

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
IEnumerable和IEnumerator 詳解
IEnumerable和IEnumerator介紹和區(qū)別
C#中要使一個(gè)類支持FOREACH遍歷,實(shí)現(xiàn)過程怎樣?
C#中的迭代器(詳解yield)
IEnumerable接口的一個(gè)簡單示例
C#中foreach語句的迭代器實(shí)現(xiàn)機(jī)制
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服