java IEnumerator_2021年了,`IEnumerator`、`IEnumerable`接口还傻傻分不清楚?

IEnumerator、IEnumerable这两个接口单词相近、含义相关,傻傻分不清楚。

入行多年,一直没有系统性梳理这对李逵李鬼。

最近本人在怼着why神的《其实吧,LRU也就那么回事》,方案1使用数组实现LRU,手写算法涉及这一对接口,借此时机覆盖这一对难缠的冤家。

IEnumerator

IEnumerator、IEnumerable接口有相似的名称,这两个接口通常也在一起使用,它们有不同的用途。

IEnumerator接口为类内部的集合提供了迭代方式, IEnumerator 要求你实现三个方法:MoveNext方法:该方法将集合索引加1,并返回一个bool值,指示是否已到达集合的末尾。

Reset方法:它将集合索引重置为其初始值-1,这会使枚举数无效。

Current方法: 返回position位置的当前对象

IEnumerable

IEnumerable接口为foreach迭代提供了支持,IEnumerable要求你实现GetEnumerator方法。public IEnumerator GetEnumerator()

{

return (IEnumerator)this;

}

该用哪一个接口?

仅凭以上辞藻,很难区分两个接口的使用场景。

IEnumerator接口定义对类中的集合类型对象的迭代方式,

IEnumerable接口允许使用foreach循环进行枚举。

因此IEnumerable接口的GetEnumerator方法会返回一个IEnumerator接口。要实现IEnumerable,你还必须实现IEnumerator。“

从英文词根上讲:

IEnumerator接口代表了枚举器,里面定义了枚举方式,是名词。

IEnumerable接口代表该对象具备了可被枚举的性质,是形容词。

总之,如果您想提供对foreach的支持,那么就先让对象可枚举,再谈论枚举方式,也就是说实现这两个接口。

最佳实践在嵌套类中实现IEnumerator,这样你可以创建多个枚举器。

为IEnumerator的Current方法提供异常处理。

为什么要这么做?

如果集合的内容发生变化,则reset方法将被调用,紧接着当前枚举数无效,您将收到一个IndexOutOfRangeException异常(其他情况也可能导致此异常)。所以执行一个Try…Catch块来捕获这个异常并引发InvalidOperationException异常, 提示在迭代时不允许修改集合内容。“

这也正是我们常见的在foreach 里面尝试修改迭代对象会报InvalidOperationException异常的原因。

下面以汽车列表为例实现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 class

private class  MyEnumerator:IEnumerator

{

public car[] carlist;

int position = -1;

//constructor

public MyEnumerator(car[] list)

{

carlist=list;

}

private IEnumerator getEnumerator()

{

return (IEnumerator)this;

}

//IEnumerator

public bool MoveNext()

{

position++;

return (position 

}

//IEnumerator

public void Reset()

{

position = -1;

}

//IEnumerator

public object Current

{

get

{

try

{

return carlist[position];

}

catch (IndexOutOfRangeException)

{

throw new InvalidOperationException();

}

}

}

}  //end nested class

public IEnumerator GetEnumerator()

{

return new MyEnumerator(carlist);

}

}

}

在foreach cars的时候,可以明显看到foreach语法糖初次接触可枚举的cars, 实际会访问cars实现的 GetEnumerator()方法,拿到迭代器

foreach每次迭代,实际会访问迭代器的Current属性

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值