为什么数组需要在定义时设置维度?

Jak*_*net 4 c# arrays

我只是想知道,为什么我们不能只定义这样的东西:

int[] arr = new int[];
arr[0] = 1;
Run Code Online (Sandbox Code Playgroud)

像列表一样,自动调整大小.我想知道的是为什么这是不可能的,我们需要按以下方式设置每次大小:

int[] arr = new int[1];
arr[0] = 1;
Run Code Online (Sandbox Code Playgroud)

Jon*_*eet 12

List<T>调整大小是基于在需要时在后台创建一个新数组.

想想这里的底层实现是什么样的.分配数组时,它会保留一块内存,并且引用有效地直接指向该内存.如果您需要存储的值多于您保留的值,则需要在其他位置分配更多内存...但是您无法更改引用以引用该新内存,因为这些引用遍布整个地方.(数组不知道它是指什么.)

显而易见的方法是拥有一个间接级别 - 这样初始引用就是一个跟踪真实数据存储位置的对象,因此它可以在需要时重新分配.这正是List<T>它的作用......但它确实意味着存在额外的间接水平.这会带来效率上的成本,部分原因在于你可能会在List对象本身的内存中留下很长的实际数据,这对于缓存来说并不好...... 而只是通过额外的间接级别本身就有成本.

基本上,如果你想要一个动态大小的集合,请使用List<T>- 这就是它的用途.如果您从一开始就知道最终尺寸并希望从阵列的"更接近金属"方面受益,请使用它们.

数组是一个相对低级的概念 - 如果你想要一个高级抽象,使用一个...

  • 也许我们应该强调你所说的内容 - 这是一个效率问题.List _can_中的间接在某个内部循环中总体上是昂贵的.我假设在许多情况下,JIT可以使数组元素访问与C数组访问一样高效,而我认为在大多数情况下访问List元素不能.因此,C#(或CLR)可能被设计为具有动态数组,就像许多脚本语言一样,但代价是在运行时变慢. (2认同)

dca*_*tro 7

由于数组在内存中是连续的,因此在创建内容时必须为其内容分配足够的内存.

假设你有一个包含100个项目的数组.现在你再添加1个,你必须在第100个项目后面声明内存地址.如果该地址已被使用怎么办?

这就是为什么你不能动态调整数组的大小.

  • 我认为这是一个后续问题,而不是主要问题.但我的答案是 - 它们是不同的抽象层次.这与询问是一回事,当我们已经有一个`ConcurrentQueue <T>`时,为什么我们需要`Queue <T>`?不同层次的抽象. (2认同)