【问题标题】:Why is an IEnumerable(or IList) implemented using arrays instead of Linked Lists?为什么使用数组而不是链接列表来实现 IEnumerable(或 IList)?
【发布时间】:2015-02-22 07:02:26
【问题描述】:

我正在阅读有关实现接口 IENumerable 的方法的基本教程,并发现所有示例都使用数组。我的印象是 IENumerable 本质上与链表非常相似。我相当有信心数组和链表是两种完全不同的数据结构。

那么,当我们实际上认为它们完全不同时,为什么要使用另一个(一个数组)来实现一个(一个链表)呢?

这是代码在 MSDN 页面上的样子:

// Collection of Person objects. This class 
// implements IEnumerable so that it can be used 
// with ForEach syntax. 
public class People : IEnumerable
{
    private Person[] _people;
    public People(Person[] pArray)
    {
        _people = new Person[pArray.Length];

        for (int i = 0; i < pArray.Length; i++)
        {
            _people[i] = pArray[i];
        }
    }

// Implementation for the GetEnumerator method.
    IEnumerator IEnumerable.GetEnumerator()
    {
       return (IEnumerator) GetEnumerator();
    }

    public PeopleEnum GetEnumerator()
    {
        return new PeopleEnum(_people);
    }
}

是否有我错过的 IENumerable 实现?

编辑:我现在明白 IENumerable 不一定类似于链表。但是,来自 MSDN 的这段代码使用数组实现了 IList:

class SimpleList : IList
{
    private object[] _contents = new object[8];
    private int _count;

    public SimpleList()
    {
        _count = 0;
    }

    // IList Members 
    public int Add(object value)
    {
        if (_count < _contents.Length)
        {
            _contents[_count] = value;
            _count++;

            return (_count - 1);
        }
        else
        {
            return -1;
        }
    }
//etc...
}

【问题讨论】:

  • 你可以用任何你想要的方式实现IEnumerable,数组恰好为此非常方便。
  • 但它在概念上不是错误的,因为数组!= 链表?
  • LinkedList&lt;T&gt;System.Array 一样实现了IEnumerable,您似乎对接口的用途感到困惑。
  • 您可能会从阅读接口中受益,IEnumerable 就是其中之一。实现IEnumerable 的方法有很多。数组、链表、从文件中读取、递增计数器、随机选取数字,唯一需要的是返回IEnumerator 的实例,而该实例又必须实现MoveNext() 方法和Current 属性。
  • @PrestonGuillot IENumerable 由LinkedList&lt;T&gt;Array 在两个单独的实现中实现是有意义的。但是在同一实现中用于实现链表的数组是我遇到问题的地方。链表是动态的。数组不是。难道在实现链表类型的数据结构中使用数组基本上会扼杀链表的动态特性吗?他们不应该分开吗?我只是在这里考虑非常基本的 DS。

标签: c# arrays data-structures ienumerable


【解决方案1】:

我的印象是 IENumerable 本质上是非常 类似于链表。

我不确定你是从哪里得到这种印象的。实现IEnumerableIEnumerable&lt;T&gt; 的对象意味着“此对象公开了一个枚举器,这使其可迭代”,它与链表或数组的实现没有直接关系。它们确实都具有可迭代的共同特征。它是对调用者有约束力的合同。

那么为什么一个(链表)要使用另一个来实现 (一个数组)当我们真正认为它们完全不同时?

链表可以有一个数组,因为它作为一个实现细节进行存储,尽管这肯定是一个糟糕的设计选择。

您可能会注意到List&lt;T&gt; 也使用数组作为其内部存储,一旦达到内部数组的最大大小,它就会重新调整大小。

【讨论】:

  • 有趣。谢谢。我刚刚编写了一个实现,它使用类似于 LinkedListNode 的东西而不是数组,但缺少一些东西,比如带参数的构造函数。
【解决方案2】:

IEnumerableIEnumerable&lt;T&gt; 不是链表。它们是提供枚举访问的接口。

这样想:IEnumerable 承诺在枚举中提供 0-n 值(例如通过使用foreach)。

许多真实的类都可以实现这个承诺。列表可以,数组可以,所有类型的集合都可以,如果您对它们进行编程,您自己的类可能会这样做。您如何将内容 放入 您的容器是特定于容器的,IEnumerable 仅说明了如何从容器中获取数据 到用它做点什么。

这是一个非常简单的解释,当您了解了这个概念后,您可能想了解延迟执行

【讨论】:

    【解决方案3】:

    简短的回答:IEnumerable 与链表“相似”,只是因为它定义了一系列值。但是一系列值也可以通过任何其他方式定义,包括作为数组。

    IEnumerable 类型是 interface。它只规定了必须公开披露的内容;它并没有以任何具体方式规定实现应该是什么。

    IEnumerable 的情况下,实现该接口的唯一事情是实现一个名为GetEnumerator() 的方法,该方法必须返回另一个接口IEnumerator 的实例。该接口必须依次实现一个名为Current 的属性,它返回一个object 的实例,以及一个名为MoveNext() 的方法,它通知IEnumerator 对象选择枚举中的下一项。

    (该接口还需要实现Reset() 方法,但该接口的许多实现只是为该方法抛出NotSupportedException……CurrentMoveNext() 成员是实现有用的最低要求界面)。

    枚举可以以适合实现它的对象的任何方式实现。 System.Linq.Enumerable 类型甚至包括简单地重复相同值若干次或发出整数序列的实现。 没有该类型的成员本身存储枚举;他们要么从头开始创建一个,要么改造一些现有的。

    同样,您可以枚举文件中的文本行,或随机选择数字,或反转数组的元素。唯一重要的是您有一些机制来选择一系列值。

    您发布的示例实际上并未向我们展示IEnumerator 的实现......有一些名为PeopleEnum 的未知类处理枚举。大概,这个类只是将一个索引存储到传递给它的对象的数组中,按顺序返回每个元素(它也可以使用"iterator method" 来实现,但它不需要一个完整的其他类型来完成它,所以我猜不是)。

    我希望以上内容不仅能帮助您解决问题。 :)

    【讨论】:

      猜你喜欢
      • 2016-11-30
      • 1970-01-01
      • 2014-12-07
      • 2010-11-12
      • 2011-02-15
      • 1970-01-01
      • 2011-08-23
      • 2017-12-21
      • 1970-01-01
      相关资源
      最近更新 更多