Массив в C# являются ссылочным типом, почему они действуют как типы значений?

согласно 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.Объект. Это означает, что все массивы всегда являются ссылочными типами, которые размещаются в управляемой куче, а переменная в приложении содержит ссылка на массив, а не на сам массив.

6 ответов


одна картина стоит тысячи слов, так что вот что происходит:

Before and After

эффект от назначения "Three" до t2 это перед назначением t1 и t2 ссылаются на один и тот же объект, но после назначения ссылаются на разные объекты. Здесь больше ничего не происходит.

ситуация была бы другой, если бы у вас был массив mutable объекты, и вместо того, чтобы манипулировать их значение устанавливать их ссылки. Например, представьте себе замену массива строк массивом StringBuilder объекты, а вызов t2.Replace("Two", "Three") вместо назначения. Теперь эффект будет другим, потому что t1, t2 и data[0] будет указывать на тот же объект.


Ваш вопрос не имеет ничего общего с массивами. С вашего data[0] is string -и это ссылочный тип - это значение One, вы никогда не изменить его значение. Вы только что создали другую строковую ссылку с именем t2 и установить точку на тот же объект с t1 ссылка. После того, как вы изменили этот ссылочный объект на "Three", но это не влияет на то, что t1 относится.

давайте посмотрим строку за строкой ваш код;

var t1 = data[0];

С помощью этой строки вы создали строковая ссылка как t1 и это не эффект t1 ссылка. Он еще указывает на


строки также являются ссылочными типами. Поэтому, если вы пишете:

var t1 = data[0];

вы объявили новую переменную t1 Это ссылается на ту же строку, что и data[0]. После этого пишешь:

var t2 = t1;

теперь у вас есть новая переменная t2 это ссылается на ту же строку, что и t1. Теперь у вас есть один String объект в куче, и три ссылки на этот объект: data[0], t1 и t2.

затем вы пиши:

t2 = "Three";

после этого заявления, t2 указывает на строку antoher в куче со значением "Three". Однако,data[0] и t1 по-прежнему указывают на ту же самую исходную строку.


писать t2 = "Three" не изменит значение t1, потому что типы являются ссылочным типом, поэтому они "указывают" на свои данные. Назначив t2 вы говорите это, чтобы ссылаться на что-то еще.

Liukewise, когда вы писали t2 = t1 ты просто говоришь t2 ссылаться на то же самое, что и t1. Будущие задания t2 просто сделает ссылку на что-то еще.

некоторые языки, такие как C++, имеют возможность хранить ссылку на другой переменные, так что при изменении ссылки вы фактически изменяете то, что является другой переменной.


эта программа точно ведет себя так, как вы ожидаете.

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 ;
}

когда вы назначаете одну переменную ссылки массива другой, вы просто обе переменные ссылаются на один и тот же массив. Вы ни вызывая копию массива, который будет создан, и вы не вызываете содержимое одного массива скопировать в другой.

// назначение ссылочных переменных массива.

        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