数组的第二个元素发生了什么?



假设我写

int numbers[] = {1,2,3};
ref int second = ref numbers[1];
Array.Resize(ref numbers, 1);
Console.WriteLine(second); // works fine
second = 321; // also legit

这是如何工作的?我是否神奇地将numbers[1]分配为托管堆上的单独可寻址号码?这是怎么回事?

Array.Resize创建一个新数组,将旧数组保留在堆上,如文档所示:

此方法分配一个具有指定大小的新数组,将元素从旧数组复制到新数组,然后用新数组替换旧数组。

(我的强调)

注意:该文档略有误导性,具体取决于您的理解方式。它说"然后用新数组替换旧数组"。这意味着它将数组变量中的引用(numbers示例中的引用)替换为对新数组的引用。旧的数组对象在内存中保持不变且保持不变。

如果你没有ref int引用,GC最终会拾取它,但既然你这样做了,它就不会。

second = 321更改原始数组,而不是新数组。

您可以使用一个非常简单的示例轻松显示这一点:

using System;
public class Program
{
public static void Main()
{
int[] a = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int[] b = a;
ref int a1 = ref a[1];
Array.Resize(ref a, 5);
a1 = 100;
Console.WriteLine(a[1]); // new
Console.WriteLine(b[1]); // original
Console.WriteLine(ReferenceEquals(a, b));
}
}

这输出:

2            // the new array, which did not change
100          // the original array, which did change
false        // not the same arrays

因此,ref int变量确实发生了变化,原始数组发生了变化,但经过大小修改的新副本没有更改。

在 .NET 小提琴上查看此示例

此方法分配一个具有指定大小的新数组,将元素从旧数组复制到新数组,然后将旧数组替换为新数组。数组必须是一维数组。

如果数组为 null,则此方法将创建具有指定大小的新数组。

如果 newSize 大于旧数组的长度,则分配一个新数组,并将所有元素从旧数组复制到新数组。如果 newSize 小于旧数组的长度,则分配一个新数组,并将元素从旧数组复制到新数组,直到填充新数组;旧数组中的其余元素将被忽略。如果 newSize 等于旧数组的长度,则此方法不执行任何操作。

直接来自 MSDN

相关内容

最新更新