C#中的数组是引用类型,为什么它们作为值类型?

时间:2015-03-13 12:26:10

标签: c# .net arrays c#-4.0

根据MSDN,如果所有数组都是引用类型,那么为什么在给定的示例代码中,t2的新值不会反映t1中的更改?

string[] data = new[] { "One", "Two" };

var t1 = data[0];

Console.WriteLine(t1);

var t2 = t1;
t2 = "Three"; //assigning the new value, and this should reflect in t1

Console.WriteLine(t2);
Console.WriteLine(t1); // this should print 'Three', but it prints 'One'

Console.Read();

enter image description here

http://msdn.microsoft.com/en-us/magazine/cc301755.aspx

  

数组是一种机制,允许您将多个项目视为一个   单一集合。 Microsoft®.NET公共语言运行时(CLR)   支持一维数组,多维数组和   锯齿状数组(数组数组)。所有数组类型都是隐式的   派生自System.Array,它本身派生自System.Object。   这意味着所有数组都是引用类型   在托管堆上分配,您的应用程序的变量包含一个   引用数组而不是数组本身。

6 个答案:

答案 0 :(得分:18)

一张图片胜过千言万语,所以这是正在发生的事情:

Before and After

"Three"t2的分配效果是在赋值t1t2之前引用相同的对象,但在赋值之后它们引用了不同的对象。这里没有其他任何事情发生。

如果你有一个可变对象数组,并且操纵它们的值而不是设置它们的引用,情况会有所不同。例如,假设用一组StringBuilder个对象替换字符串数组,并调用t2.Replace("Two", "Three")而不是赋值。现在效果会有所不同,因为t1t2data[0]会指向同一个对象。

答案 1 :(得分:8)

您的问题与数组无关。由于您的data[0]string - 并且它是引用类型 - 它的值为One,因此您永远不会更改它的值。您刚刚创建了另一个名为t2的字符串引用,并使用t1引用将其指向同一个对象。将此引用对象更改为"Three"后,但这不会影响t1引用的内容。

让我们逐行查看您的代码;

var t1 = data[0];

使用此行,您创建了一个字符串引用t1,这指向"One"对象。

var t2 = t1;

使用此行,您可以创建一个新的字符串引用t2,并指向t1 "One"的同一个对象

t2 = "Three";

使用此行,您将创建一个名为"Three"的字符串对象,并且您的t2将引用此对象。它不再指向"One"对象 。但是这个不会影响t1引用。 仍然指向"One"对象。

这就是为什么

Console.WriteLine(t2);
Console.WriteLine(t1);

打印

Three
One

答案 2 :(得分:7)

字符串也是引用类型。所以,如果你写:

var t1 = data[0];

您已声明一个新变量t1,该变量引用与data[0]相同的字符串。在此之后你写道:

var t2 = t1;

现在您有了一个新变量t2,它引用了与t1相同的字符串。您现在在堆上有一个String对象,以及对该对象的三个引用:data[0]t1t2

然后你写:

t2 = "Three";

在此语句之后,t2指向堆中具有值"Three"的antoher字符串。但是,data[0]t1仍然指向相同的原始字符串。

答案 3 :(得分:0)

t2 = "Three"不会改变t1的值,因为类型是引用类型,所以它们"指向"他们的数据。通过分配给t2,您可以告诉它引用其他内容。

Liukewise,当你写t2 = t1时,你只是告诉t2引用与t1相同的内容。对t2的未来分配只会使其引用其他内容。

某些语言(如C ++)确实能够存储对其他变量的引用,因此当您更改引用时,实际上会更改其他变量的内容。

答案 4 :(得分:0)

这个程序完全符合您的预期。

void Main()
{
    abc[] data = new[] { new abc(){i=1}, new abc(){i=2} };

var t1 = data[0];
var t2 = t1;
// here is the difference 
// t2 is still pointing to its old location
// but i will point a new position.
t2.i  = 5 ; //assigning the new value to i
// but t2 still pointing to t1
//all will be identical now.
Console.WriteLine(t2);
Console.WriteLine(t1); 
Console.WriteLine(data[0]);


  // repeating like you.
  t2 = new abc() {i=444};
 //now you will see t2 is different form t1. because
 // now t2 pointing to a new object instead of t1.
 Console.WriteLine(t2);
Console.WriteLine(t1);


}

public class abc{
    public int i ;
}

答案 5 :(得分:-1)

  

当你将一个数组引用变量分配给另一个时,你就是   简单地让两个变量都引用同一个数组。你不是   导致创建数组的副本,也不会导致   要复制到另一个数组的一个数组的内容。

     

//分配数组引用变量。

        using System; class AssignARef {
     static void Main()
     {
 int i; 
    int[] nums1 = new int[10];
     int[] nums2 = new int[10]; 
    for(i=0; i < 10; i++)
     nums1[i] = i;
     for(i=0; i < 10; i++)
     nums2[i] = -i;
     Console.Write("Here is nums1: "); 
    for(i=0; i < 10; i++)
     Console.Write(nums1[i] + " ");
     Console.WriteLine();
     Console.Write("Here is nums2: ");
     for(i=0; i < 10; i++)
     Console.Write(nums2[i] + " "); 
    Console.WriteLine(); nums2 = nums1; // now nums2 refers to nums1 
    Console.Write("Here is nums2 after assignment: "); 
    for(i=0; i < 10; i++)
     Console.Write(nums2[i] + " "); 
    Console.WriteLine(); // Next, operate on nums1 array through nums2. 
    nums2[3] = 99; 
    Console.Write("Here is nums1 after change through nums2: ");
     for(i=0; i < 10; i++) 
    Console.Write(nums1[i] + " ");
     Console.WriteLine(); 

}
 }
  

O / P

Here is nums1: 0 1 2 3 4 5 6 7 8 9
Here is nums2: 0 -1 -2 -3 -4 -5 -6 -7 -8 -9
Here is nums2 after assignment: 0 1 2 3 4 5 6 7 8 9
Here is nums1 after change through nums2: 0 1 2 99 4 5 6 7 8 9