C# 编写自定义IEnumerator<;T>;使用迭代器

C# 编写自定义IEnumerator<;T>;使用迭代器,c#,iterator,C#,Iterator,如何编写一个自定义的IEnumerator实现,它需要维护一些状态,并且仍然可以使用迭代器块来简化它?我能想到的最好的办法是: public class MyEnumerator<T> : IEnumerator<T> { private IEnumerator<T> _enumerator; public int Position {get; private set;} // or some other custom properties

如何编写一个自定义的
IEnumerator
实现,它需要维护一些状态,并且仍然可以使用迭代器块来简化它?我能想到的最好的办法是:

public class MyEnumerator<T> : IEnumerator<T> {
    private IEnumerator<T> _enumerator;
    public int Position {get; private set;} // or some other custom properties

    public MyEnumerator() {
        Position = 0;
        _enumerator = MakeEnumerator();
    }

    private IEnumerator<T> MakeEnumerator() {
        // yield return something depending on Position
    } 

    public bool MoveNext() {
        bool res = _enumerator.MoveNext();
        if (res) Position++;
        return res;
    }

    // delegate Reset and Current to _enumerator as well
}

public class MyCollection<T> : IEnumerable<T> {

    IEnumerator<T> IEnumerable<T>.GetEnumerator() {
        return GetEnumerator();
    }

    public MyEnumerator<T> GetEnumerator() {
        return new MyEnumerator<T>();
    }

    ...
}
公共类MyEnumerator:IEnumerator{
私有IEnumerator_枚举器;
public int Position{get;private set;}//或其他一些自定义属性
公共分子(){
位置=0;
_枚举器=MakeEnumerator();
}
私有IEnumerator MakeEnumerator(){
//根据位置返回某物
} 
公共图书馆{
bool res=_枚举数.MoveNext();
if(res)Position++;
返回res;
}
//也将重置和当前委托给_枚举器
}
公共类MyCollection:IEnumerable{
IEnumerator IEnumerable.GetEnumerator(){
返回GetEnumerator();
}
公共分子GetEnumerator(){
返回新分子();
}
...
}

为什么要编写迭代器类?迭代器块的整个要点是,您不必

i、 e

或者,如果您只有一个枚举器:

while(iter.MoveNext()) {
   position++;
   yield return iter.Current;
}

您还可以考虑将状态(作为元组)添加到您所得到的事物:

class MyState<T> {
    public int Position {get;private set;}
    public T Current {get;private set;}
    public MyState(int position, T current) {...} // assign
}
...
yield return new MyState<Foo>(position, item);

在这一点上,我不得不同意马克的观点。如果你真的想(仅仅是因为你能?)的话,你可以完全自己编写一个枚举器类,或者简单地使用一个interator块并产生语句,然后完成它。就我个人而言,我再也不接触枚举器类了。;-)

马克·格拉威尔

但是如果可能,避免编写迭代器类。它们是大量的工作,很容易出错

这正是我想在迭代器中使用
yield
机制来完成繁重工作的原因

您还可以考虑将状态(作为元组)添加到您所得到的事物:

class MyState<T> {
    public int Position {get;private set;}
    public T Current {get;private set;}
    public MyState(int position, T current) {...} // assign
}
...
yield return new MyState<Foo>(position, item);
是的,行得通。然而,每一步都需要额外的分配。如果我在大多数步骤中只对
T
感兴趣,如果我可以避免的话,这是我不需要的开销

然而,你最后的建议给了我一个想法:

public IEnumerator<T> GetEnumerator(Action<T, int> action) {
    int position = 0; // state
    while(whatever) {
        position++;
        var t = ...something...;
        action(t, position);
        yield return t;
    }
}

public IEnumerator<T> GetEnumerator() {
    return GetEnumerator(DoNothing<T, int>());
}
public IEnumerator GetEnumerator(操作){
int位置=0;//状态
尽管(不管怎样){
位置++;
var t=…某物。。。;
动作(t,位置);
收益率t;
}
}
公共IEnumerator GetEnumerator(){
返回GetEnumerator(DoNothing());
}

我制作了一个非常简单的迭代器,它借用了默认的枚举器来完成大部分(实际上是全部)工作。构造函数接受一个
IEnumerator
,我的实现只需将工作交给它即可。我在自定义迭代器中添加了一个
索引
字段

我在这里举了一个简单的例子:

要使用此迭代器设置,您的自定义集合/列表类中会有如下内容:

public class MyList<T> : List<T>{
    public new IEnumerator<T> GetEnumerator(){
        return new IndexedEnumerator<T>(base.GetEnumerator());
    }
}

正如我所说,我真的不想:)大多数人都在寻找这是为了更好地理解。我被要求在应用程序中进行编程测试。仅供参考。有趣-ForEach的懒惰版本;当然,它确实复制了T(一次在yield中,一次在action/invoke中),但很有趣。我正在研究内部枚举器“while(iter.MoveNext())…[etc]”的情况:我们不是在这里泄漏“iter”实例吗?自动生成的外部枚举器不会知道“iter”应该被释放,对吗?@toong如果迭代器块去掉了一些IDisposable,那么它应该使用
using
语句-在大多数正常使用情况下,该语句将被正确清除,
0: a
1: b
2: c
public IEnumerator<T> GetEnumerator(Action<T, int> action) {
    int position = 0; // state
    while(whatever) {
        position++;
        var t = ...something...;
        action(t, position);
        yield return t;
    }
}

public IEnumerator<T> GetEnumerator() {
    return GetEnumerator(DoNothing<T, int>());
}
public class MyList<T> : List<T>{
    public new IEnumerator<T> GetEnumerator(){
        return new IndexedEnumerator<T>(base.GetEnumerator());
    }
}
public static class Helpers{
    //Extension method to get the IndexEnumerator
    public static IndexedEnumerator<T> GetIndexedEnumerator<T>(this IEnumerable<T> list){
        return new IndexedEnumerator<T>(list.GetEnumerator());
    }
}

//base Enumerator methods/implementation
public class BaseEnumerator<T> : IEnumerator<T>{
    public BaseEnumerator(IEnumerator<T> enumer){
        enumerator = enumer;
    }

    protected virtual IEnumerator<T> enumerator{get;set;}

    protected virtual T current {get;set;}

    public virtual bool MoveNext(){
        return enumerator.MoveNext();
    }

    public virtual IEnumerator<T> GetEnumerator(){
        return enumerator;
    }

    public virtual T Current {get{return enumerator.Current;}}

    object IEnumerator.Current {get{return enumerator.Current;}}

    public virtual void Reset(){}

    public virtual void Dispose(){}
}

public class IndexedEnumerator<T> : BaseEnumerator<T>
{
    public IndexedEnumerator(IEnumerator<T> enumer):base(enumer){}

    public int Index {get; private set;}

    public override bool MoveNext(){
        Index++;
        return enumerator.MoveNext();
    }
}