When should I separately implement IEnumerator<T>?

风格不统一 提交于 2019-12-12 12:06:07

问题


In the framework classes of collections I have often seen IEnumerator<T> separately implemented as an inner class and an instance of it is returned in the GetEnumerator method.

Now suppose I'm writing my own collection classes which will have an inbuilt collection like List<T> or T[] act as the holder internally, say like this:

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

Should I be writing my own enumerator class, or is it ok to return enumerator of the List<T> class? Is there any circumstance under which should I be writing my own enumerator class?


I have a related question as well. If it's not all that important or doesn't make much of a difference, why do every collection class in the BCL write their own IEnumerator?

For eg, List<T> class has something like

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

回答1:


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/




回答2:


Just to answer one part:

List<T> has its own enumerator implementation for two reasons:

  • It can't just return the iterator of its backing array, because:
    • It needs to detect structural changes in the list (additions and removals) in order to invalidate the enumerator
    • The array may well be larger than the list. (Using Take would fix this, at the cost of another level of indirection)
  • The above could be performed with an iterator block (although there'd have to be a non-iterator method first, in order to capture the "structural version" of the list at call time rather than first iteration time), but that's relatively inefficient compared with the actual highly-optimized mutable struct implementation

Using a mutable struct here has certain issues, but when used in the expected fashion, it avoids heap allocations, virtual method calls via references etc.



来源:https://stackoverflow.com/questions/24142614/when-should-i-separately-implement-ienumeratort

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!