2021年了,`IEnumerator`、`IEnumerable`接口还傻傻分不清楚?
IEnumerator、IEnumerable這兩個(gè)接口單詞相近、含義相關(guān),傻傻分不清楚。
入行多年,一直沒有系統(tǒng)性梳理這對(duì)李逵李鬼。
最近本人在懟著why神的《其實(shí)吧,LRU也就那么回事》,方案1使用數(shù)組實(shí)現(xiàn)LRU,手寫算法涉及這一對(duì)接口,借此時(shí)機(jī)覆蓋這一對(duì)難纏的冤家。
IEnumerator
IEnumerator、IEnumerable接口有相似的名稱,這兩個(gè)接口通常也在一起使用,它們有不同的用途。
IEnumerator接口為類內(nèi)部的集合提供了迭代方式, IEnumerator 要求你實(shí)現(xiàn)三個(gè)方法:
MoveNext方法:該方法將集合索引加1,并返回一個(gè)bool值,指示是否已到達(dá)集合的末尾。
Reset方法:它將集合索引重置為其初始值-1,這會(huì)使枚舉數(shù)無效。
Current方法: 返回position位置的當(dāng)前對(duì)象
IEnumerable
IEnumerable接口為foreach迭代提供了支持,IEnumerable要求你實(shí)現(xiàn)GetEnumerator方法。
public?IEnumerator?GetEnumerator() {return?(IEnumerator)this; }該用哪一個(gè)接口?
僅憑以上辭藻,很難區(qū)分兩個(gè)接口的使用場(chǎng)景。
IEnumerator接口定義對(duì)類中的集合類型對(duì)象的迭代方式,
IEnumerable接口允許使用foreach循環(huán)進(jìn)行枚舉。
因此IEnumerable接口的GetEnumerator方法會(huì)返回一個(gè)IEnumerator接口。要實(shí)現(xiàn)IEnumerable,你還必須實(shí)現(xiàn)IEnumerator。
“從英文詞根上講:
IEnumerator接口代表了枚舉器,里面定義了枚舉方式,是名詞。
IEnumerable接口代表該對(duì)象具備了可被枚舉的性質(zhì),是形容詞。
總之,如果您想提供對(duì)foreach的支持,那么就先讓對(duì)象可枚舉,再談?wù)撁杜e方式,也就是說實(shí)現(xiàn)這兩個(gè)接口。
最佳實(shí)踐
在嵌套類中實(shí)現(xiàn)IEnumerator,這樣你可以創(chuàng)建多個(gè)枚舉器。
為IEnumerator的Current方法提供異常處理。
為什么要這么做?
如果集合的內(nèi)容發(fā)生變化,則reset方法將被調(diào)用,緊接著當(dāng)前枚舉數(shù)無效,您將收到一個(gè)IndexOutOfRangeException異常(其他情況也可能導(dǎo)致此異常)。所以執(zhí)行一個(gè)Try…Catch塊來捕獲這個(gè)異常并引發(fā)InvalidOperationException異常, 提示在迭代時(shí)不允許修改集合內(nèi)容。
這也正是我們常見的在foreach 里面嘗試修改迭代對(duì)象會(huì)報(bào)InvalidOperationException異常的原因。
下面以汽車列表為例實(shí)現(xiàn)IEnumerator IEnumerable接口
using?System; using?System.Collections; namespace?ConsoleEnum {public?class?cars?:?IEnumerable{private?car[]?carlist;//Create?internal?array?in?constructor.public?cars(){carlist=?new?car[6]{new?car("Ford",1992),new?car("Fiat",1988),new?car("Buick",1932),new?car("Ford",1932),new?car("Dodge",1999),new?car("Honda",1977)};}//private?enumerator?classprivate?class??MyEnumerator:IEnumerator{public?car[]?carlist;int?position?=?-1;//constructorpublic?MyEnumerator(car[]?list){carlist=list;}private?IEnumerator?getEnumerator(){return?(IEnumerator)this;}//IEnumeratorpublic?bool?MoveNext(){position++;return?(position?<?carlist.Length);}//IEnumeratorpublic?void?Reset(){position?=?-1;}//IEnumeratorpublic?object?Current{get{try{return?carlist[position];}catch?(IndexOutOfRangeException){throw?new?InvalidOperationException();}}}}??//end?nested?classpublic?IEnumerator?GetEnumerator(){return?new?MyEnumerator(carlist);}} }在foreach cars的時(shí)候,可以明顯看到
foreach語(yǔ)法糖初次接觸可枚舉的cars, 實(shí)際會(huì)訪問cars實(shí)現(xiàn)的 GetEnumerator()方法,拿到迭代器
foreach每次迭代,實(shí)際會(huì)訪問迭代器的Current屬性
關(guān)注并星標(biāo)我們
更多干貨及最佳實(shí)踐分享
總結(jié)
以上是生活随笔為你收集整理的2021年了,`IEnumerator`、`IEnumerable`接口还傻傻分不清楚?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【One by One系列】Identi
- 下一篇: 浅谈与彼得原理和责任管理有关的小故事