方法Array.Clone是浅拷贝?

时间:2013-11-23 17:39:28

标签: c# .net

克隆是浅层复制的一种方式。 string是引用类型。为什么s2的变化不能影响s1?

    private void button3_Click(object sender, EventArgs e)
    {
        string[] s1 = { "a", "b" };
        string[] s2 = new string[2];

        s2 = (string[])s1.Clone();
         //s2=s1; //when Direct assignment s1 changed too
        s2[1] = "e";
        foreach (var s in s1)
        {
            this.richTextBox1.Text += s+",";
        }
        this.richTextBox1.Text += System.Environment.NewLine;

        foreach (var s in s2)
        {
            this.richTextBox1.Text += s + ",";
        }
    }
}

输出: A,B, A,E, 当浅拷贝时,它应该是:a,e,a,e

4 个答案:

答案 0 :(得分:4)

当你克隆 s1s2时,这些是两个完全独立的对象,住在不同的位置。

s1[1]包含对b所占位置的引用,s2[1]也是如此。然后,您可以为s2[1]分配不同的引用 - 一个引用到不同的位置。这不会以任何方式影响s1[1]

毕竟,你没有改变持有b的位置。


当您指定s2 = s1;时,两个变量都指向同一个对象 - 当您更改该对象时,两个变量都会反映变化,因为它们指向同一个位置。

答案 1 :(得分:2)

无论是浅拷贝还是深拷贝,复制总是会创建一个新实例。这意味着更改复制的对象不会影响原始对象。请注意,当我说更改复制的对象时,我的意思是您将一些元素分配给一个全新的实例。如果只更改该元素的某些属性,它可以反映原始数组中的相应元素(当然,如果元素类型是引用类型)。但在这种情况下,元素只是一个字符串,它是不可变的,我们无法改变它。

关于浅拷贝和深拷贝,这里有点MSDN

  

Array的浅表副本仅复制Array的元素,无论它们是引用类型还是值类型,但它不会复制引用引用的对象。新数组中的引用指向与原始数组中的引用指向的相同对象。

     

相比之下,Array的深层副本会复制元素以及元素直接或间接引用的所有内容。

我想更多地强调这个更改元素的属性并不意味着更改数组。并且更改数组意味着您必须将一些元素分配给一个全新的实例

答案 2 :(得分:2)

你所要求的是不可能的,因为字符串是不可变的,这意味着它们不能被分配(Why .NET String is immutable?处的更多信息),因此每次分配字符串时,它实际上是创建一个新字符串并替换对象。

如果你想获得你想要的效果,你可能希望将s2指定给s1,这会使它们指向同一个数组,并具有所需的效果。


浅拷贝的一个例子是: (假设定义了label1和label2)

Label[] s1 = new Label[2];
Label[] s2 = new Label[2];
s1[0] = label1;
s1[1] = label2;
for (int i = 0; i < s1.Length; i++)
    s2[i] = s1[i];
s2[1].Text = "asdf";

在最终结果中,s1 [1]的Text属性将更改为“asdf”,因为即使数组不同,s1 [1]和s2 [1]也指向同一个对象。

注意: s2 [1] = new Label()不会改变s1 [1]因为对象s2 [1]指向正在改变(基本上是什么s2 [1] =“asdf”;正在OP的代码中做),但那是任何浅拷贝的限制。

答案 3 :(得分:0)

运行以下程序。我想我是对的。 CopyTo以及Clone正在执行卷影复制。

namespace ConsoleApplication5
{
    public class Person
    {
       public static void Main( string[] args)
       {
            StringBuilder a = new StringBuilder("Vish");
            StringBuilder b = new StringBuilder("Krish");
            StringBuilder[] arr = new  StringBuilder[2] { a,b };
            StringBuilder[] copied = new  StringBuilder[2];


            arr.CopyTo(copied, 0);

            StringBuilder[] cloned = arr.Clone() as  StringBuilder[];

            Console.WriteLine();

            copied[1] = copied[1].Append("_AppendedCopy");
            cloned[1] = cloned[1].Append("_AppendedClone");

            for (int i = 0; i < arr.Length; i++)
                Console.WriteLine(arr[i]);
            Console.WriteLine();
            for (int i = 0; i < copied.Length; i++)
                Console.WriteLine(copied[i]);
            Console.WriteLine();

            for (int i = 0; i < cloned.Length; i++)
                Console.WriteLine(cloned[i]);
            Console.WriteLine();

            Console.ReadKey();
        }
    }
}