4

在集合的框架类中,我经常看到IEnumerator<T>单独实现为内部类,并在GetEnumerator方法中返回它的实例。

现在假设我正在编写自己的集合类,它将有一个内置的集合,例如List<T>T[]在内部充当持有者,像这样说:

public class SpecialCollection<T> : IEnumerable<T>
{
    List<T> list;

    public SpecialCollection<T>()
    {

    }

    public IEnumerator<T> GetEnumerator()
    {
        return list.GetEnumerator();

        //or
        return list.Where(x => some logic).GetEnumerator(); 

        //or directly rely on yield keyword
        yield return x; //etc
    }
}

我应该编写自己的枚举器类,还是可以返回List<T>该类的枚举器?在什么情况下我应该编写自己的枚举器类?


我也有一个相关的问题。如果它不是那么重要或没有太大区别,为什么 BCL 中的每个集合类都编写自己的IEnumerator

例如,List<T>类有类似的东西

T[] items;
public IEnumerator<T> GetEnumerator()
{
    return new List<T>.Enumerator(items);
}
4

2 回答 2

7

The answer to your first question is: when a yield return doesn't meet your needs.

The answer to your second question is: these heavily used types have performance requirements that are unusually strict, so the enumerators are custom built. I've written some articles on this recently; see:

http://ericlippert.com/2014/05/21/enumerator-advance/

http://ericlippert.com/2014/06/04/enumerator-bounds/

于 2014-06-10T13:50:45.510 回答
2

只回答一部分:

List<T>有自己的枚举器实现有两个原因:

  • 它不能只返回其支持数组的迭代器,因为:
    • 它需要检测列表中的结构变化(添加和删除)以使枚举器无效
    • 数组可能比列表大。(使用Take会解决这个问题,代价是另一个间接级别)
  • 上面可以使用迭代器块执行(尽管首先必须有一个非迭代器方法,以便在调用时而不是第一次迭代时捕获列表的“结构版本”),但这相对低效与实际高度优化的可变结构实现相比

在这里使用可变结构有一些问题,但是当以预期的方式使用时,它避免了堆分配、通过引用调用虚拟方法等。

于 2014-06-10T15:45:02.853 回答