数组与List <T>:何时使用哪个?

Fre*_*ool 561 .net arrays list

MyClass[] array;
List<MyClass> list;
Run Code Online (Sandbox Code Playgroud)

当一个优于另一个时,有什么情况?为什么?

Mar*_*ell 550

实际上,您很少想要使用数组.绝对可以List<T>随时使用添加/删除数据,因为调整数组大小非常昂贵.如果您知道数据是固定长度的,并且您希望根据某些非常具体的原因进行微优化(在基准测试之后),那么数组可能会很有用.

List<T>提供了很多更多的功能不是一个数组(虽然LINQ找齐它一点),而且几乎总是正确的选择.params当然,除了争论.;-p

作为反击 - List<T>是一维的; 在哪里 - 因为你有矩形(等)数组,int[,]或者string[,,]- 但是在对象模型中还有其他方法可以建模这些数据(如果需要).

也可以看看:

也就是说,我在protobuf-net项目中大量使用了数组; 完全是为了表现:

  • 它会进行大量的位移,所以a byte[]对编码非常重要;
  • 我使用一个本地滚动byte[]缓冲区,在发送到底层流(和vv)之前我填充; 比BufferedStream等更快;
  • 它在内部使用基于数组的对象模型(Foo[]而不是List<Foo>),因为大小一旦构建就固定,并且需要非常快.

但这绝对是个例外; 对于一般的业务线处理,List<T>每次都获胜.

  • 更多功能==更复杂==不好,除非你需要这些功能.这个答案基本上列出了为什么数组更好的原因,但得出了相反的结论. (12认同)
  • @EamonNerbonne如果你不使用这些功能,我几乎可以保证它们不会伤害你......但是:根据我的经验,从不需要变异的集合数量要小得多****比那些变异的 (11认同)
  • 关于调整大小的论点是完全有效的.然而,即使不需要调整大小,人们也更喜欢列表.对于后一种情况,是否存在一个可靠的逻辑论证,或者它只不过是"数组不合时宜"? (7认同)
  • @MarcGravell:这取决于你的编码风格.根据我的经验,几乎没有任何收藏品发生变异.那是; 从数据库中检索集合或从某些源构建集合,但总是通过重新创建新集合(例如,映射/过滤器等)来完成进一步处理.即使在需要概念变异的地方,最简单的方法就是生成新的集合.我只是将集合变异为性能优化,并且这种优化往往是高度本地化的,并且不会将变异暴露给API使用者. (7认同)
  • "当你想要添加/删除数据时,绝对可以使用List <T>,因为调整数组的大小非常昂贵." List <T>在内部使用数组.你在想LinkedList <T>吗? (6认同)
  • @Dangph:List <T>使数组保持大于它需要的大小,因此并非每个添加/删除操作都需要调整数组大小,因为大多数时候数组末尾仍然有空闲空间. (3认同)
  • @EamonNerbonne 我完全不同意“大多数代码”不需要调整数组大小,并且如果您使用数组,还有很多其他事情您必须担心会出错。 (2认同)
  • @EamonNerbonne Arrays 在您*需要*一个可变集合但长度固定的相当罕见的情况下是最佳选择。那根本就不是函数式编程。 (2认同)
  • @barlop k; `int[,]` 明确是一个二维数组。`int[,,]` 明确是一个 3d 数组。然而,`int[][]` 不是“二维数组”——它是一维数组的一维数组,也就是锯齿状数组。同样,`List&lt;List&lt;int&gt;&gt;` 不是一个二维列表:它是一个列表列表。关键是在`int[,]`的情况下,有**一个数组**,所以我们可以描述这1个数组的属性。在`List&lt;List&lt;int&gt;&gt;`的情况下,有n+1个列表;一个是一维列表列表,什么时候是一维整数列表。是的,您可以使用 `List&lt;List&lt;int&gt;&gt;` 来表示 2D 数据,但这不是一回事。语义很重要。 (2认同)

Jon*_*eet 117

真的只是回答添加一个我很惊讶的链接尚未被提及:Eric的Lippert的博客文章"Arrays被认为有些危害".

您可以从标题中判断它建议在任何实际情况下使用集合 - 但正如Marc正确指出的那样,有很多地方阵列确实是唯一实用的解决方案.

  • 哈哈,终于在3年后阅读了这篇文章.那么好文章,好文章吧.:) (2认同)

Aln*_*tak 20

尽管推荐了其他答案List<T>,但您还是希望在处理时使用数组:

  • 图像位图数据
  • 其他低级数据结构(即网络协议)

  • @Konrad - 好吧,对于初学者来说,Stream.Read和Stream.Write与byte []一起工作,编码等... (8认同)

Spe*_*ort 11

除非你真的关心性能,我的意思是"你为什么使用.Net而不是C++?" 你应该坚持使用List <>.它更容易维护,并为您在幕后调整阵列大小的所有脏工作.(如果需要,List <>非常聪明地选择数组大小,因此通常不需要.)

  • "你为什么使用.Net而不是C++?" XNA (13认同)
  • 详细说明@Bengt 的评论,性能不是.NET 的首要任务,但这无论如何都是公平的。但一些聪明的人想到了将 .NET 与游戏引擎结合使用。事实上,现在大多数游戏引擎都使用 C#。在这方面,Unity 3D 是“当游戏引擎不适合 AAA 时”的典范。 (2认同)
  • @mireazma 很长一段时间以来这都不是一个有效的声明(相对于 Unity)。我们通过 HPC# 和 Burst 从 C# 中获得 C++ 性能。许多引擎内部正在迁移到 C#。即使您谈论的是非 DOTS 项目中的游戏脚本,IL2CPP 在生成高性能代码方面也做得非常非常好。 (2认同)

Her*_*eld 6

当集合本身的不变性是客户端和提供者代码之间的契约的一部分(不一定是集合中项目的不变性)和IEnumerable不适合时,应该优先使用数组.

例如,

var str = "This is a string";
var strChars = str.ToCharArray();  // returns array
Run Code Online (Sandbox Code Playgroud)

很明显,"strChars"的修改不会改变原始的"str"对象,而与"str"的底层类型的实现级知识无关.

但是假设那样

var str = "This is a string";
var strChars = str.ToCharList();  // returns List<char>
strChars.Insert(0, 'X');
Run Code Online (Sandbox Code Playgroud)

在这种情况下,单独的代码片段不清楚插入方法是否会改变原始的"str"对象.它需要String的实现级知识才能做出决定,从而打破了"按合同设计"的方法.在String的情况下,它并不是什么大问题,但在几乎所有其他情况下它都是一个大问题.将List设置为只读确实有帮助,但会导致运行时错误,而不是编译时.


sma*_*007 5

如果我知道我到底有多少元素去需求,说我需要5元,仅5元,然后我使用一个数组。否则我只使用 List<T>。


Mel*_*per 5

数组与数组 列表是一个典型的可维护性与性能问题。几乎所有开发人员都遵循的经验法则是,您应该同时兼顾两者,但当它们发生冲突时,请选择可维护性而不是性能。该规则的例外是当性能已被证明是一个问题时。如果你将这个原则应用到数组与数组中。列表,然后你得到的是这样的:

使用强类型列表,直到遇到性能问题。如果遇到性能问题,请确定退出到阵列是否对您的解决方案的性能有好处,而不是对您的解决方案的维护造成损害。

  • 这切入了我们必须面对的核心业务决策,时间就是金钱,数组通常会比对象的列表或集合花费更多的时间来开发和维护,尤其是多维数组。但在许多情况下,它们会带来较小的性能和内存占用成本 (2认同)