何时应单独实现IEnumerator<T>?

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);
}

1
相对于什么?许多这些类是在迭代器出现之前编写的。 - SLaks
1
泛型是在yield关键字引入的同时引入的,如果我没记错的话。 - Dennis_E
1
@JeppeStigNielsen 我认为 // some logic 的意思是可以向枚举器中添加一些额外的逻辑。 - Maarten
1
@Maarten 假设我编写了自己的类型 class MyColl : IEnumerable<int>。我可以在内部使用数组来保存我的值,因此有一个字段 private int[] array;。现在,当我需要实现泛型接口时,我不能只说 return array.GetEnumerator();(编译时错误),因为数组(这里是 int[])不太通用。我可以通过 return array.Select(x => x).GetEnumerator(); 来解决这个问题。但那是浪费的。相反,使用 return ((IEnumerable<int>)array).GetEnumerator(); 或等效地使用 return array.AsEnumerable().GetEnumerator();。你明白我的意思吗? - Jeppe Stig Nielsen
3
如果你返回数组的 IEnumerator<T>,那么不能在调用之间检测到列表更改,这应该会引发异常。 - Jon Skeet
显示剩余16条评论
2个回答

7

2

仅回答部分问题:

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

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

在此处使用可变结构体存在某些问题,但是当按预期方式使用时,它避免了堆内存分配、通过引用进行虚拟方法调用等。


数组长度是另一个容易被忽视的重要点。但我认为从框架中返回内置类型(如字典、列表、栈、队列、集合等,当然不包括数组)的枚举器是可以的,因为它们的枚举器可以处理这个集合修改问题。不是吗? - nawfal
@nawfal:在什么情况下返回枚举器?通常可以,但有时不行。这里没有一种适合所有情况的答案。 - Jon Skeet
我指的是与我在问题中提供的示例相同的情况。如果我的类SpecialCollection<T>的支持集合类型为List<T>,那么从SpecialCollection<T>.GetEnumerator方法返回List<T>.GetEnumerator是无误的,我想。 - nawfal
1
@nawfal:是的,如果您没有其他特殊要求,我认为那应该没问题。 - Jon Skeet
我明白了,谢谢。 - nawfal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接