我什么时候应该单独实现IEnumerator <t>?</t>

时间:2014-06-10 13:41:35

标签: c# .net enumerator ienumerator design-guidelines

在集合的框架类中,我经常看到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);
}

2 个答案:

答案 0 :(得分:7)

第一个问题的答案是:当收益率回报不符合您的需求时。

第二个问题的答案是:这些使用频繁的类型具有异常严格的性能要求,因此枚举器是自定义构建的。我最近写了一些文章;见:

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

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

答案 1 :(得分:2)

回答一个部分:

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

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

在这里使用可变结构has certain issues,但是当以期望的方式使用时,它避免了堆分配,通过引用的虚方法调用等。