编写自定义IEnumerator< T>与迭代器 [英] Writing custom IEnumerator<T> with iterators

查看:103
本文介绍了编写自定义IEnumerator< T>与迭代器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何编写自定义 IEnumerator< T> 实现,它需要维护某些状态并仍然可以使用迭代器块来简化它?我能想到的最好的是这样的:

How can I write a custom IEnumerator<T> implementation which needs to maintain some state and still get to use iterator blocks to simplify it? The best I can come up with is something like this:

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

    ...
}


推荐答案

为什么要编写迭代器类?迭代器块的重点是你不必...

Why do you want to write an iterator class? The whole point of an iterator block is so you don't have to...

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

如果添加更多上下文(i,e,为什么以上都行不通),我们可以提供更多帮助。

If you add more context (i,e, why the above can't work), we can probably help more.

但如果可能,请避免编写迭代器类。他们工作很多,而且很容易出错。

But if possible, avoid writing an iterator class. They are lots of work, and easy to get wrong.

顺便说一下,你真的不必为重置 - 它在很大程度上已被弃用,并且不应该被使用(因为它不能被用于任意枚举器)。

By the way, you don't really have to bother with Reset - it is largely deprecated, and shouldn't really ever be used (since it can't be relied to work for an arbitrary enumerator).

如果你想要使用内部迭代器,也没关系:

If you want to consume an inner iterator, that is fine too:

int position = 0;
foreach(var item in source) {
   position++;
   yield return position;
}

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

or if you only have an enumerator:

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

你也可以考虑将状态(作为元组)添加到你的东西yield:

You might also consider adding the state (as a tuple) to the thing you 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);

最后,您可以使用LINQ样式的扩展/委托方法, Action< int,T> 为调用者提供位置和值:

Finally, you could use a LINQ-style extension/delegate approach, with an Action<int,T> to supply the position and value to the caller:

    static void Main() {
        var values = new[] { "a", "b", "c" };
        values.ForEach((pos, s) => Console.WriteLine("{0}: {1}", pos, s));            
    }
    static void ForEach<T>(
            this IEnumerable<T> source,
            Action<int, T> action) {
        if (source == null) throw new ArgumentNullException("source");
        if (action == null) throw new ArgumentNullException("action");

        int position = 0;
        foreach (T item in source) {
            action(position++, item);
        }
    }

输出:

0: a
1: b
2: c

这篇关于编写自定义IEnumerator&lt; T&gt;与迭代器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆