3

以下に示す 2 セットのコード スニペットの出力を理解できません。浅いコピーの概念を実際に理解していないのはどうしてですか。どのように説明できますか?

クラス:

 public class Person : ICloneable
 {
    public string Name;        
    public int[] arr; 
    public object Clone()
    {
        return this.MemberwiseClone();
    }
 }

コード スニペット 1:

 static void Main(string[] args)
    {
        Person p1 = new Person();
        p1.Name = "Name1";
        p1.arr = new int[5] {1,2,3,4,5 };
        Person p2 = (Person)p1.Clone();

        p1.Name = "Name2";
        p1.arr[0] = 11;

        Console.WriteLine(p2.Name);
        Console.WriteLine(p2.arr[0].ToString());
        Console.Read();

    }

出力: Name1 11

疑問: string は参照型ではありませんか。次に、スニペット 1 で p2.Name が「Name1」として出力される理由

コード スニペット 2:

static void Main(string[] args)
    {
        Person p1 = new Person();
        p1.Name = "Name1";
        p1.arr = new int[5] { 1, 2, 3, 4, 5 };
        Person p2 = (Person)p1.Clone();

        p1.Name = "Name2";
        p1.arr = new int[5] { 11, 12, 13, 14, 15 };

        Console.WriteLine(p2.Name);
        Console.WriteLine(p2.arr[0].ToString());
        Console.Read();

    }

出力: 名前1 1

4

4 に答える 4

4

あなたの例の int[] 配列は参照型です。つまり、 と の両方がメモリ内の同じ配列p1.arrp2.arr指しているということです。

の最初のインデックスの値を変更すると、 の最初のインデックスのp1.arrp2.arrも変更されます。したがって、コード スニペット 1 の動作です。

2 番目のコード スニペットの違いは、p1 の配列への参照を変更することです。さて、p1.arr新しいオブジェクトへの参照です。p2.arr「元の」配列への参照を保持しています。したがって、printingp2.arr[0]は 1 を出力します。

編集

うまくいけば、いくつかの疑いを取り除くために、次のように入力したことを覚えていれば、より明確になるかもしれません。

p1.Name = "Name2";

実際には:

p1.Name = new String("Name2");

これは int[] 配列とまったく同じです。の値を変更しているのではなくp1.Name、新しい文字列オブジェクトを作成していて、p1.Nameの参照をこの新しい文字列オブジェクトに変更しています。p2.Name は、「元の」文字列オブジェクト、つまり「Name1」への独自の参照を保持しています。の参照を変更してもp1.Nameその参照は変更されません。

于 2009-04-08T12:59:43.857 に答える
2

元の質問での疑問を軽減するために。

文字列は確かに参照型です。覚えておくべきことは、配列に対して行っていることと文字列に対して行っていることは同じではないということです。

p1.Name = "Name2"; // new String - p1.Name と同等 = new string("Name2")
p1.arr[0] = 11; //更新された配列要素

配列の場合、参照されているメモリの一部のデータを変更しています。String の場合、(新しいメモリ位置に) 新しい文字列を作成し、参照である p1.Name を、新しく割り当てられたメモリを指すようにします。p2.Name (別の参照) は、文字 "Name1" が格納されている元のメモリ位置を指したままです

余談ですが、文字列の不変性により、p1.Name の変更が p2.Name に反映されることはありません。string.replace などの文字列を変更しようとすると、メモリ内に新しい文字列が作成されます。

それが役立つことを願っています。

于 2009-04-08T13:30:00.803 に答える
2

http://msdn.microsoft.com/en-us/library/system.object.memberwiseclone.aspxから

MemberwiseClone メソッドは、新しいオブジェクトを作成し、現在のオブジェクトの非静的フィールドを新しいオブジェクトにコピーすることによって浅いコピーを作成します。フィールドが値型の場合、フィールドのビットごとのコピーが実行されます。フィールドが参照型の場合、参照はコピーされますが、参照されるオブジェクトはコピーされません。したがって、元のオブジェクトとそのクローンは同じオブジェクトを参照します。

于 2009-04-08T12:49:26.440 に答える
0

Pls はインライン コメントを参照してください。

static void Main(string[] args)
{
    Person p1 = new Person();
    p1.Name = "Name1";
    p1.arr = new int[5] {1,2,3,4,5 };
    Person p2 = (Person)p1.Clone();

    p1.Name = "Name2"; //Now p1.Name points to a new memory location
    //But p2.Name is still pointing to the location p1.Name had
    // originally pointed to.

    p1.arr[0] = 11; //here p1.arr and p2.arr are pointing to the same place
    //So since you are changing the value of one location it gets 
    //reflected in both

    Console.WriteLine(p2.Name); //Prints Name1
    Console.WriteLine(p2.arr[0].ToString()); //Prints 11
    Console.Read();

}

あなたが言うときの2番目のスニペットで

p1.arr = new int[5] { 11, 12, 13, 14, 15 };

p1.arr は、まったく新しい場所を指すように作成されます。(p1.Name = "Name2"を実行するとどうなるかのように)したがって、p1.arrが以前に指していたのと同じ場所をまだ指しているp2.arrには反映されません。(つまり、配列 {1,2,3,4,5} に)

于 2009-04-08T19:29:43.513 に答える