C# 列表和序列之间的区别

C# 列表和序列之间的区别,c#,f#,list,sequences,C#,F#,List,Sequences,我试图理解序列和列表之间的区别 在F#中,两者之间有着明显的区别。然而,在C#中,我看到程序员将IEnumerable集合称为序列。是什么使IEnumerable成为一个序列的事实是它返回一个对象来遍历集合 也许真正的区别纯粹是在函数式语言中发现的?不是真的-你倾向于对列表进行随机访问,并且能够快速获得其计数等。无可否认,链表不具有随机访问的性质。。。但是他们没有实现IList。特定平台提供的设施与一般概念之间存在灰色地带 序列(由IEnumerable表示)是只读的、只向前的、一次一项的,并且

我试图理解序列和列表之间的区别

在F#中,两者之间有着明显的区别。然而,在C#中,我看到程序员将IEnumerable集合称为序列。是什么使IEnumerable成为一个序列的事实是它返回一个对象来遍历集合


也许真正的区别纯粹是在函数式语言中发现的?

不是真的-你倾向于对列表进行随机访问,并且能够快速获得其计数等。无可否认,链表不具有随机访问的性质。。。但是他们没有实现IList。特定平台提供的设施与一般概念之间存在灰色地带


序列(由
IEnumerable
表示)是只读的、只向前的、一次一项的,并且可能是无限的。当然,序列的任何一个实现也可能是一个列表(例如,
list
),但当您将其视为一个序列时,您基本上可以(重复地)迭代它,就是这样。

我认为混淆可能是因为像
list
这样的集合实现了接口
IEnumerable
。如果您通常具有子类型关系(例如,超类型
形状
具有两个子类型
矩形
圆形
),则可以将该关系解释为“is-a”层次结构

这意味着说“
是一个
形状
”是完全正确的,同样,人们会说“
列表
是一个
IEnumerable
”,也就是说,“列表是一个序列”。这是有道理的,因为列表是序列的一种特殊类型。通常,序列也可以是惰性生成的和无限的(这些类型也不能是列表)。列表无法生成的(完全有效)序列示例如下所示:

// C# version                           // F# version
IEnumerable<int> Numbers() {            let rec loop n = seq {
  int i = 0;                               yield n
  while (true) yield return i++;           yield! loop(n + 1) }
}                                       let numbers = loop(0)
//C#version//F#version
IEnumerable Numbers(){let rec loop n=seq{
int i=0;收益率n
while(true)yield return i++;yield!loop(n+1)}
}让数字=循环(0)

对于F#也是如此,因为F#
list
类型也实现了
IEnumerable
,但函数式编程并没有把重点放在面向对象的观点上(而在F#中使用隐式转换来实现“is a”解释的频率较低).

序列内容是按需计算的,因此您可以在不影响内存的情况下实现例如无限序列。 例如,在C语言中,你可以编写一个序列

IEnumerable<int> Null() {
  yield return 0;
}
它需要10*4字节的内存,尽管序列是无限的。
正如你所看到的,C#在序列和集合之间确实有区别

+1很好的解释-这是一个模糊的区别,但很重要的一点是要理解的。转发怎么可能只能“基本上(重复地)对它进行迭代”?@Jeb50:因为每次调用
GetEnumerator()
,它都会返回一个新的迭代器。一个实现只允许调用一次是可行的,但是大多数实现都允许重复迭代。所以就像每次克隆它一样,理解“重复”?@Jeb50:这取决于你所说的“克隆”的意思和实现的功能。例如,
List
实现只是在每次调用
GetEnumerator()
时在列表上创建一个新的“光标”。禁止克隆。另一个实现可以在每次调用
GetEnumerator()
时为您提供一个随机(可能无限)序列,而无需克隆。另一个实现(例如ConcurrentDictionary)可以在每次调用
GetEnumerator
时拍摄快照。
int[] array = Null().Take(10).ToArray()