在阅读帖子时,一些要点没有示例:
要实现IEnumerable / IEnumerable,您必须提供枚举器:
•如果该类正在“包装”另一个集合,则返回包装集合的枚举器。
•通过使用yield return的迭代器。
•通过实例化您自己的IEnumerator / IEnumerator实现
(我的宝贝大脑将其解释为)
(第1点)
If the class is "wrapping" another collection, by returning the
wrapped collection's enumerator.
意思是......
class StringCollections
{
//A class is wrapping another collection
string[] names=new string {“Jon Skeet”,”Hamish Smith”,
”Marc Gravell”,”Jrista”,”Joren”};
//by returning the wrapped collection’s enumerator
public IEnumerator GetEnumerator( )
{
// What should I return here ?
//like the following ?
yield return names[0];
yield return names[1];
yield return names[2];
....
(or)
foreach(string str in names)
{
yield return str;
}
}
}
(第2点)
•Via an iterator using yield return.(This point was well explained
by Marc Gravell)
第3点
By instantiating your own IEnumerator/IEnumerator<T> implementation*
点3代表什么?,因为没有例子,我没有得到那个。 这是否意味着,我可以构建自定义枚举器..(对吧?)。我的问题是预制枚举器/枚举器是否足够(作为一个初学者,我不应该盲目地证实这一点) 迭代为什么我应该照顾自定义的?好的例子将澄清我的怀疑。
感谢您阅读这篇冗长的故事并做出回应。
答案 0 :(得分:3)
(第1点) 您可以将GetEnumerator的调用链接到其他集合枚举器:
public class PrimeNumbers : IEnumerable
{
public IEnumerator GetEnumerator()
{
var primes = new List<int> { 2, 3, 5, 7, 11 };
return primes.GetEnumerator();
}
}
(第2点) 与您的代码中的示例类似
public IEnumerator GetEnumerator()
{
var primes = new List<int> { 2, 3, 5, 7, 11 };
foreach (var number in primes)
{
yield return number;
}
}
或者将枚举器放在逻辑中:
public class PrimeNumbers : IEnumerable
{
public IEnumerator GetEnumerator()
{
for(int i=2; ;i++)
{
if(IsPrime(i))
{
yield return i;
}
}
}
}
(第3点) 您想要实现自己的枚举器的情况并不多,但例如,您可以查找一组无限的值,例如:素数:
public class PrimeNumbers : IEnumerable
{
public IEnumerator GetEnumerator()
{
return new MyEnumerator();
}
}
public class MyEnumerator : IEnumerator
{
private int lastPrimeNumber = 1;
public bool MoveNext()
{
lastPrimeNumber = /* some logic that find the next prime */;
return true; // There is always next prime
}
public void Reset()
{
lastPrimeNumber = 1;
}
public object Current
{
get { return lastPrimeNumber; }
}
}
用法示例可能是:
public void PrintAllPrimes()
{
var numbers = new PrimeNumbers();
// This will never end but it'll print all primes until my PC crash
foreach (var number in numbers)
{
Console.WriteLine(number);
}
}
优点&amp;我能想到的缺点:
答案 1 :(得分:2)
这是一个例子:(注意:这是简化的,而不是线程安全的例子)
public class PersonCollection : IEnumerable
{
private ArrayList alPers = new ArrayList();
public IEnumerator GetEnumerator() { return new myTypeEnumerator(this); }
public class myTypeEnumerator : IEnumerator
{
int nIndex;
PersonCollection pers;
private int count { get { return pers.alPers.Count; } }
public myTypeEnumerator(PersonCollection myTypes)
{ pers = myTypes; nIndex = -1; }
public bool MoveNext() { return nIndex <= count && ++nIndex < count; }
// MovePrev() not strictly required
public bool MovePrev() { return (nIndex > -1 && --nIndex > 0 ); }
public object Current { get { return (pers[nIndex]); } }
public void Reset() { nIndex = -1; }
}
}
编辑:修复@Joren引发的问题,下面与Move Previous相关,索引值低于-1。当框架作为foreach实现的一部分调用时,MoveNext()不需要此修复,因为在这种情况下如果MoveNext()返回false,则枚举实例将终止。但是,如果客户端手动调用MoveNext(),枚举器将不会终止,因此它也需要修复。
另外注意:你如何在这件事中实现细节取决于你,并将取决于它如何在内部管理状态。例如,如果保存引用的iunternal“bucket”是链表而不是ArrayList,那么可以通过仅将Current字段更改为指向旧当前的nextItem属性来实现MoveNext()...
答案 2 :(得分:1)
你所说的1实际上是2。
对于1,它更像是
public IEnumerator GetEnumerator() {
return names.GetEnumerator();
}
对于第3点,它意味着让GetEnumerator做一些真正的工作:手动为你定义的集合实现一个Enumerator。
答案 3 :(得分:0)
“如果该类正在”包装“另一个集合,则通过返回包装集合的枚举器”意味着:
class StringCollections{
//A class is wrapping another collection
string[] names=new string {“Jon Skeet”,”Hamish Smith”,
”Marc Gravell”,”Jrista”,”Joren”};
public IEnumerator GetEnumerator() { return names.GetEnumerator(); }
}