原文链接:
https://www.php.cn/csharp-article-357797.html
C# IEnumerable和IEnumerator接口的简单介绍
Foreach常用于循环访问集合,对实现IEnumerable的接口的容器进行遍历,IEnumerable和IEnumerator接口我有时候也有点迷糊,按官方的解释,IEnumerable是枚举器接口,IEnumerator是迭代器接口,从字面意思来看相差不大,逐一分析一下。
IEnumerable接口
public interface IEnumerable
{
IEnumerator GetEnumerator();
}
|
继承IEnumerable接口的类需实现暴露出来的GetEnumerator()方法,并返回一个IEnumerator接口对象,看来真正做事的是IEnumerator,F12看一下IEnumerator又有什么鬼东西。
IEnumerator接口
public interface IEnumerator
{
object Current { get ; }
bool MoveNext();
void Reset();
}
|
IEnumerator接口有三个东东,一个属性Current,返回当前集合中的元素,方法MoveNext()移动到下一个,遍历不都是向后遍历的嘛,Reset(),字面意思重置,这个容易理解。做个假设:既然IEnumerable接口返回是IEnumerator接口迭代器来实现的,那么仅继承IEnumerator迭代器接口能不能实现一个自定义容器?
定义一个Phone类
public class Phone
{
public string Name;
public Phone( string name)
{
this .Name = name;
}
}
|
定义一个名为MyEnumerator迭代器,并现实它接口IEnumerator
public class MyEnumerator : IEnumerator
{
Phone[] p;
int idx = -1;
public MyEnumerator(Phone[] t)
{
p = t;
}
public object Current
{
get
{
if (idx == -1)
return new IndexOutOfRangeException();
return p[idx];
}
}
public bool MoveNext()
{
idx++;
return p.Length > idx;
}
public void Reset()
{
idx = -1;
}
}
|
class Program
{
static void Main( string [] args)
{
show( "-----------IEnumerator------------" );
Phone[] phones = new Phone[] { new Phone( "iPhone 7s" ), new Phone( "iPhone 6s" ), new Phone( "iPhone 5s" ) };
MyEnumerator enumerator = new MyEnumerator(phones);
while (enumerator.MoveNext())
{
Phone p = enumerator.Current as Phone;
show(p.Name);
}
Console.ReadKey();
}
static void show( string i)
{
Console.WriteLine(i);
}
}
|
结果显示:
果然不出所料,真正做事情的是IEnumerator接口,即可循环访问自定义的一个容器,不过,初衷是想用Foreach来做循环访问、遍历的。那好,那就只能显示IEnumerable接口来做。稍稍改造一下Phone类:
public class Phone : IEnumerable
{
public string Name ;
public Phone( string name)
{
this .Name = name;
}
Phone[] p;
public Phone(Phone[] t)
{
p = t;
}
public IEnumerator GetEnumerator()
{
return new MyEnumerator(p);
}
}
|
static void Main( string [] args)
{
show( "-----------IEnumerator------------" );
Phone[] phones = new Phone[] { new Phone( "iPhone 7s" ), new Phone( "iPhone 6s" ), new Phone( "iPhone 5s" ) };
MyEnumerator enumerator = new MyEnumerator(phones);
while (enumerator.MoveNext())
{
Phone p = enumerator.Current as Phone;
show(p.Name);
}
show( "-----------IEnumerable------------" );
Phone phoneList = new Phone(phones);
foreach (Phone p in phoneList)
{
show(p.Name);
}
Console.ReadKey();
}
|
结果显示:
大功告成,再扩展成通用的容器PhonePackage,继承泛型IEnumerable<T>接口即可。
public class PhonePackage<T> : IEnumerable<T>
{
private List<T> dataList = null ;
public void Add(T t)
{
if (dataList == null )
dataList = new List<T>();
dataList.Add(t);
}
public IEnumerator<T> GetEnumerator()
{
foreach (T t in dataList)
{
yield return t;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
foreach (T t in dataList)
{
yield return t;
}
}
}
|
static void Main( string [] args)
{
show( "-----------IEnumerator------------" );
Phone[] phones = new Phone[] { new Phone( "iPhone 7s" ), new Phone( "iPhone 6s" ), new Phone( "iPhone 5s" ) };
MyEnumerator enumerator = new MyEnumerator(phones);
while (enumerator.MoveNext())
{
Phone p = enumerator.Current as Phone;
show(p.Name);
}
show( "-----------IEnumerable------------" );
Phone phoneList = new Phone(phones);
foreach (Phone p in phoneList)
{
show(p.Name);
}
show( "-----------IEnumerable<T>------------" );
PhonePackage<Phone> phonePackage = new PhonePackage<Phone>();
phonePackage.Add( new Phone( "iPhone 7s" ));
phonePackage.Add( new Phone( "iPhone 6s" ));
phonePackage.Add( new Phone( "iPhone 5s" ));
foreach (Phone p in phonePackage)
{
show(p.Name);
}
Console.ReadKey();
}
static void show( string i)
{
Console.WriteLine(i);
}
|
结果显示:
IEnumerator迭代器接口挺啰嗦的,yield是简化了遍历的语法糖而已。