IEnumerable 、 IEnumerator 与 foreach,何时使用什么

发布于 2024-07-27 00:54:45 字数 135 浏览 4 评论 0原文

我正在浏览 IEnumerable 和 IEnumerator ,但无法清楚地得到一点..如果我们有 foreach,那么为什么我们需要这两个接口? 有没有什么场景我们必须使用接口。如果是,那么有人可以用例子解释一下吗? 欢迎任何建议和意见。 谢谢。

I was going through IEnumerable and IEnumerator , but could not get one point clearly..if we have foreach, then why do we need this two interfaces? Is there any scenario where we have to use interfaces.If yes, then can somebody explain with an example.
Any suggestions and remarks are welcome.
Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

雄赳赳气昂昂 2024-08-03 00:54:45

foreach 在许多情况下使用接口。 如果您想实现一个可供foreach 使用的序列,则需要这些接口。 (尽管迭代器块通常使这个实现任务变得非常简单。)

但是,偶尔直接使用迭代器可能会很有用。 一个很好的例子是尝试“配对”两个不同的序列。 例如,假设您收到两个序列 - 一个是姓名,一个是年龄,并且您想将这两个序列一起打印。 您可能会写:

static void PrintNamesAndAges(IEnumerable<string> names, IEnumerable<int> ages)
{
    using (IEnumerator<int> ageIterator = ages.GetEnumerator())
    {
        foreach (string name in names)
        {
            if (!ageIterator.MoveNext())
            {
                throw new ArgumentException("Not enough ages");
            }
            Console.WriteLine("{0} is {1} years old", name, ageIterator.Current);
        }
        if (ageIterator.MoveNext())
        {
            throw new ArgumentException("Not enough names");
        }

    }
}

同样,如果您想以不同于其他的方式对待(比如说)第一项,那么使用迭代器可能会很有用:

public T Max<T>(IEnumerable<T> items)
{
    Comparer<T> comparer = Comparer<T>.Default;

    using (IEnumerator<T> iterator = items.GetEnumerator())
    {
        if (!iterator.MoveNext())
        {
            throw new InvalidOperationException("No elements");
        }
        T currentMax = iterator.Current;

        // Now we've got an initial value, loop over the rest
        while (iterator.MoveNext())
        {
            T candidate = iterator.Current;
            if (comparer.Compare(candidate, currentMax) > 0)
            {
                currentMax = candidate;
            }
        }
        return currentMax;
    }
}

现在,如果您对 IEnumerator 之间的差异感兴趣> 和 IEnumerable,您可能需要用数据库术语来思考它:将 IEnumerable 视为表格,将 IEnumerator视为表格。 作为光标。 您可以要求表给您一个新的游标,并且您可以同时在同一个表上有多个游标。

可能需要一段时间才能真正理解这种差异,但只要记住列表(或数组,或其他什么)没有任何“你在列表中的位置”的概念,而是在该列表/数组/任何<上的迭代器em>确实有这样的状态是有帮助的。

foreach uses the interfaces in many cases. You need the interfaces if you want to implement a sequence which foreach can then use. (Iterator blocks usually make this implementation task very simple though.)

However, just occasionally it can be useful to use the iterators directly. A good example is when trying to "pair up" two different sequences. For example, suppose you receive two sequences - one of names, one of ages, and you want to print the two together. You might write:

static void PrintNamesAndAges(IEnumerable<string> names, IEnumerable<int> ages)
{
    using (IEnumerator<int> ageIterator = ages.GetEnumerator())
    {
        foreach (string name in names)
        {
            if (!ageIterator.MoveNext())
            {
                throw new ArgumentException("Not enough ages");
            }
            Console.WriteLine("{0} is {1} years old", name, ageIterator.Current);
        }
        if (ageIterator.MoveNext())
        {
            throw new ArgumentException("Not enough names");
        }

    }
}

Likewise it can be useful to use the iterator if you want to treat (say) the first item differently to the rest:

public T Max<T>(IEnumerable<T> items)
{
    Comparer<T> comparer = Comparer<T>.Default;

    using (IEnumerator<T> iterator = items.GetEnumerator())
    {
        if (!iterator.MoveNext())
        {
            throw new InvalidOperationException("No elements");
        }
        T currentMax = iterator.Current;

        // Now we've got an initial value, loop over the rest
        while (iterator.MoveNext())
        {
            T candidate = iterator.Current;
            if (comparer.Compare(candidate, currentMax) > 0)
            {
                currentMax = candidate;
            }
        }
        return currentMax;
    }
}

Now, if you're interested in the difference between IEnumerator<T> and IEnumerable<T>, you might want to think of it in database terms: think of IEnumerable<T> as a table, and IEnumerator<T> as a cursor. You can ask a table to give you a new cursor, and you can have multiple cursors over the same table at the same time.

It can take a while to really grok this difference, but just remembering that a list (or array, or whatever) doesn't have any concept of "where you are in the list" but an iterator over that list/array/whatever does have that bit of state is helpful.

扮仙女 2024-08-03 00:54:45

乔恩说的话。

  • IEnumerableIEnumerable :通过实现此对象,它可以为您提供一个迭代器,您可以使用它来遍历序列/集合/集合
  • IEnumeratorIEnumerator :如果调用前面接口中定义的 GetEnumerator 方法,您将获得一个迭代器对象作为 IEnumerator 引用。 这使您能够调用 MoveNext() 并获取 Current 对象。
  • foreach :从某种意义上说,它是一个 C# 构造/外观,因为您不需要知道它在幕后是如何工作的。 它在内部获取迭代器并调用正确的方法,以便您专注于要对每个项目(foreach 块的内容)执行的操作。 大多数时候,您只需要 foreach ,除非您要实现自己的类型或自定义迭代,在这种情况下,您需要了解前两个接口。

What Jon said.

  • IEnumerable or IEnumerable<T> : by implementing this an object states that it can give you an iterator that you can use to traverse over the sequence/collection/set
  • IEnumerator or IEnumerator<T> : if you call the GetEnumerator method defined in the previous interface, you get an iterator object as an IEnumerator reference. This enables you to call MoveNext() and get the Current object.
  • foreach : is a C# construct/facade in a sense in that you don't need to know how it works under the hood. It internally gets the iterator and calls the right methods for you to concentrate on what you want to do with each item (the contents of the foreach block). Most of the time, you'd just need foreach unless you're implementing your own type or custom iteration, in which case you'd need to get to know the first 2 interfaces.
野心澎湃 2024-08-03 00:54:45

请记住,您不必必须实现 IEnumerator 及其变体来使用 foreach - IIRC,它所需要的只是一个 GetEnumerator() 方法,该方法返回一个对象,该对象具有一个 MoveNext() 方法,该方法返回bool 和返回对象的 Current 属性。 您不需要使用 IEnumerator 和 IEnumerable,尽管这样做通常是一个非常好的主意。 请参阅此处 了解更多信息。

Bear in mind that you don't have to implement IEnumerator and varients thereof to use foreach - IIRC, all it needs is a GetEnumerator() method that returns an object that has a MoveNext() method returning a bool, and a Current property returning an object. You don't need to use IEnumerator and IEnumerable, although it generally is a very good idea to do so. See here for more information.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文