我怀疑这背后有一些我完全没有注意到的真正根本的东西。我可以写
int b = 5;
int a = b;
a = 2;
据我所知,这给了我两个独立的变量。最初,a 设置为 5,但随后我可以将 a 更改为 2而无需更改 b
但是,我可以写
double[] b = { 1, 2, 3, 4};
double[] a = b;
a[2] = 9;
现在,似乎我没有两个单独的变量,而是对同一实体有 2 个引用。改变 a[2] 现在改变 b[2]。这是怎么回事?
我怀疑这背后有一些我完全没有注意到的真正根本的东西。我可以写
int b = 5;
int a = b;
a = 2;
据我所知,这给了我两个独立的变量。最初,a 设置为 5,但随后我可以将 a 更改为 2而无需更改 b
但是,我可以写
double[] b = { 1, 2, 3, 4};
double[] a = b;
a[2] = 9;
现在,似乎我没有两个单独的变量,而是对同一实体有 2 个引用。改变 a[2] 现在改变 b[2]。这是怎么回事?
C#中有两种类型的变量。第一个称为“值”类型。当您为其分配一个值时,该值将复制到该位置,因此当您编写
int b = a;
您正在将 a 的值复制到 b。
但是,还有一个“参考”类型。这只会复制对变量的引用- 换句话说,它会获得变量的一种句柄,因此当对该变量进行更改时,它们会在两个地方反映出来。
值类型包括struct
s 和所有原语 - 整数、双精度、字符等,字符串除外。引用类型就是其他一切。
一些评论者已经提供了很好的链接,所以我不会在这里添加任何内容。
在 C# 中,数组是引用类型。看到这个
虽然我认为这最终会成为一个重复的问题,但我很抱歉没有在链接上进一步阐述。
在 C# 中,您有值类型和引用类型。所有数组(即使它们是值类型的数组)都是引用类型。
值类型的行为与您的第一个示例中一样,存储其值所需的内存分配在堆栈上,堆栈在包含对象的范围内生存和死亡。
引用类型仅存储指向堆上分配内存的位置的指针,并且它一直存在,直到垃圾收集器确定没有任何东西不再使用它并且可以清理它。因此,如果将一个引用类型分配给另一个引用类型,它们就是同一个对象,但名称不同。
这当然过于简单化了,但是您可以在我的答案中的链接或解决同一主题的任何精彩的 SO 问题中获得更多信息。
.NET 中有两种类型,值类型和引用类型。int 是值类型,double[] 是数组,是引用类型。
您的第一个a = b
分配 b (它只保存值 5)到a
。在您的第二个示例b
中,引用内存中的数组,并且a = b
简单地指向a
同一个数组。
标准数组行为。
如果您使用简单=
运算符,将传递一个引用,然后您操作原始对象。
为了防止这种行为使用内置函数.CopyTo()
或Array.Clone()
a.CopyTo(b, 0)
b = a.Clone();
当您现在更改 b 时,将不会更改 a。
警告:
仅在确保 b 可以包含 a (b.Length >= a.Length) 的所有元素后才使用此函数,否则将抛出索引超出范围异常
在您的第一个示例中, int 是一个值类型,每个都被分配一个内存位置。在第二个示例中,数组是复杂数据类型或引用类型,因此 a 被分配为指针。