web-dev-qa-db-ja.com

浅いコピーまたは深いコピー?

1つのオブジェクトを別のオブジェクトにコピーするこれら2つの方法に少し慣れています。私は混乱しており、ディープコピーとシャローコピーの大きな違いを見つけることができません。 。 ->

   class A
    {
        public int a = 0;
        public void display()
        {
            Console.WriteLine("The value of a is " + a);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            A ob1 = new A();
            ob1.a = 10;
            ob1.display();
            A ob2 = new A();
            ob2 = ob1;
            ob2.display();
            Console.Read();
        }
    }

これは浅いコピーですか、それとも深いコピーですか?誰でも理由を答えてください。ディープコピーの場合、オブジェクトコピーの同じジョブを実行するこのプログラムの浅いコピーのコードを提供してください。

上記が浅いコピーである場合、これでさえ浅いコピーでなければなりません->

            A ob1 = new A();
            ob1.a = 10;
            ob1.display();
            A ob2 = ob1;
            ob2.a = 444;
            ob1.display();
33

リンクから こちら

浅いコピーの複製は可能な限り少なくします。コレクションの浅いコピーは、要素ではなくコレクション構造のコピーです。浅いコピーでは、2つのコレクションが個々の要素を共有するようになりました。

ディープコピーはすべてを複製します。コレクションのディープコピーは、元のコレクションのすべての要素が複製された2つのコレクションです。

あなたの例は浅いコピーを作成しています。

A ob1 = new A();
ob1.a = 10;
A ob2 = new A();
ob2 = ob1;

ob1.a = 5; // <-- If you see value of ob2.a after this line, it will be 5.

ディープコピーは-

 A ob1 = new A();
 ob1.a = 10;
 A ob2 = new A();
 ob2.a = ob1.a;

 ob1.a = 5; // <-- If you see value of ob2.a after this line, it will be 10.
55
Rohit Vats

私の意見では、厳密な浅いコピーまたは深いコピーではありません。定義する必要がある場合、浅いコピーと言います。

ob2 = ob1;このコードは、両方が同じオブジェクトを参照する2つのオブジェクト参照を作成します。したがって、ob1を介して行われたオブジェクトへの変更は、ob2の後続の使用に反映されます。

MSDNの例では、浅いコピー、深いコピー、および単にクラスコピーの違いを説明する方が良いでしょう。

 using System;

    public class IdInfo
    {
        public int IdNumber;

        public IdInfo(int IdNumber)
        {
            this.IdNumber = IdNumber;
        }
    }

    public class Person
    {
        public int Age;
        public string Name;
        public IdInfo IdInfo;

        public Person ShallowCopy()
        {
            return (Person)this.MemberwiseClone();
        }

        public Person DeepCopy()
        {
            Person other = (Person)this.MemberwiseClone();
            other.IdInfo = new IdInfo(this.IdInfo.IdNumber);
            other.Name = String.Copy(this.Name);
            return other;
        }
    }

    public class Example
    {
        public static void Main()
        {
            // Create an instance of Person and assign values to its fields.
            Person p1 = new Person();
            p1.Age = 42;
            p1.Name = "Sam";
            p1.IdInfo = new IdInfo(6565);

            // Perform a shallow copy of p1 and assign it to p2.
            Person p2 = (Person)p1.ShallowCopy();

            // Display values of p1, p2
            Console.WriteLine("Original values of p1 and p2:");
            Console.WriteLine("   p1 instance values: ");
            DisplayValues(p1);
            Console.WriteLine("   p2 instance values:");
            DisplayValues(p2);

            // Change the value of p1 properties and display the values of p1 and p2.
            p1.Age = 32;
            p1.Name = "Frank";
            p1.IdInfo.IdNumber = 7878;
            Console.WriteLine("\nValues of p1 and p2 after changes to p1:");
            Console.WriteLine("   p1 instance values: ");
            DisplayValues(p1);
            Console.WriteLine("   p2 instance values:");
            DisplayValues(p2);

            // Make a deep copy of p1 and assign it to p3.
            Person p3 = p1.DeepCopy();
            // Change the members of the p1 class to new values to show the deep copy.
            p1.Name = "George";
            p1.Age = 39;
            p1.IdInfo.IdNumber = 8641;
            Console.WriteLine("\nValues of p1 and p3 after changes to p1:");
            Console.WriteLine("   p1 instance values: ");
            DisplayValues(p1);
            Console.WriteLine("   p3 instance values:");
            DisplayValues(p3);

            // Make an equal of p1 and assign it to p4.
            Person p4 = new Person();
            p4 = p1;
            // Change the members of the p1 class to new values to show the equal copy.
            p1.Name = "Will";
            p1.Age = 30;
            p1.IdInfo.IdNumber = 8484;
            Console.WriteLine("\nValues of p1 and p4 after changes to p1:");
            Console.WriteLine("   p1 instance values: ");
            DisplayValues(p1);
            Console.WriteLine("   p4 instance values:");
            DisplayValues(p4);
        }

        public static void DisplayValues(Person p)
        {
            Console.WriteLine("      Name: {0:s}, Age: {1:d}", p.Name, p.Age);
            Console.WriteLine("      Value: {0:d}", p.IdInfo.IdNumber);
        }
    }

結果は次のとおりです。

Original values of p1 and p2:    p1 instance values:
      Name: Sam, Age: 42
      Value: 6565    p2 instance values:
      Name: Sam, Age: 42
      Value: 6565

Values of p1 and p2 after changes to p1:    p1 instance values:
      Name: Frank, Age: 32
      Value: 7878    p2 instance values:
      Name: Sam, Age: 42
      Value: 7878

Values of p1 and p3 after changes to p1:    p1 instance values:
      Name: George, Age: 39
      Value: 8641    p3 instance values:
      Name: Frank, Age: 32
      Value: 7878

Values of p1 and p4 after changes to p1:    p1 instance values:
      Name: Will, Age: 30
      Value: 8484    p4 instance values:
      Name: Will, Age: 30
      Value: 8484
16
Will Yu

これは浅いコピーでも深いコピーでもありません。これは参照コピーです。説明させてください。変数には2つのタイプがあります。値のタイプと参照のタイプです。

値型は、変数の実際の値を保持するコンピューターメモリ内の(名前の付いた)場所です。例:intは値型であるため、次のコード行を記述すると:

int MyInt = 5;

このコード行が実行されると、ランタイムはRAMで場所を見つけ、その中に値5を書き込みます。その場所を検索すると、実際の値5が見つかります。

対照的に、参照型は、実際には変数の値を保持しないが、その値が存在するメモリの位置を保持するメモリ内の(名前の付いた)場所です。例として、次のコードを書いたと仮定します。

MyClass myObject = new MyClass();

何が起こるかというと、仮想マシン(ランタイム):1-メモリ内の利用可能な場所を探して見つけ、MyClassクラスのインスタンスを作成します。そのオブジェクトの場所がたまたまRAMのバイト#AA3D2にあったと言うことができます。

2-メモリ内の場所を見つけ、タイプMyClassの参照を作成します(参照とは、メモリ内の場所を指す「矢印」です)。名前を「myObject」とし、値AA3D2を格納します。

「myObject」変数を見ると、クラスインスタンスではなく、そのクラスインスタンスを保持するメモリの場所を表すAA3D2が見つかります。

次に、OPを指定してコードを調べます。

A ob1 = new A();

これにより、ob1という変数が作成され、Aクラスのインスタンスが作成され、そのクラスの場所がob1に保存されます。

ob1.a = 10;
ob1.display();

これにより、Aクラス内の変数aが変更されます。次に、display()メソッドを呼び出します

A ob2 = new A();

ここでは、ob2という変数を作成し、クラスAのインスタンスを作成し、その場所をob2に割り当てます。

これで、Aの2つのクラスインスタンスと、それぞれがそれらの1つを指している2つの変数がメモリ内にあります。ここからが興味深い部分です。ob2= ob1;

変数ob2には変数ob1の値が割り当てられます。 ob1にはAの最初のインスタンスのメモリ位置が含まれているため、ob1とob2の両方がメモリ内の同じ位置を指します。それらのいずれかを使用して何かを行うことは、もう一方とまったく同じシンを行うことです。

ob2 = ob1は、参照をコピーしていることを意味します。

5
EKanadily

Ob2の変数を変更してからob1を印刷しようとすると、それらは同じになるため、これは浅いコピーです。これは、C#のクラスであるものがクラス間のリンクを作成するためです。ディープコピーを行う場合は、コピーメソッドを実装し、フィールドを手動でコピーする必要があります。何かのようなもの:

  class A
    {
        public int a = 0;
        public void display()
        {
            Console.WriteLine("The value of a is " + a);
        }

       public A Copy()
    {
        A a = new A();
        a.a = = this.a;
        return a;
    }



    }
2
Vaughan Hilts

@docesamからの回答と@Will Yuからの回答の一部を支持します。

これは浅いコピーでも深いコピーでもありません。これは参照コピーです。 -ドセサム


ob2 = ob1;このコードは、両方が同じオブジェクトを参照する2つのオブジェクト参照を作成します。したがって、ob1を介して行われたオブジェクトへの変更は、ob2の以降の使用に反映されます。 -ウィル・ウィル


MSDN(備考を参照) によると:

配列の浅いコピーは、それらが参照型または値型であるかどうかにかかわらず、配列の要素のみをコピーしますが、参照が参照するオブジェクトはコピーしません。新しい配列の参照は、元の配列の参照が指すのと同じオブジェクトを指します。

ここで、注意すべきことが2つあります。

  1. 浅いコピーは要素をコピーします。
  2. 浅いコピーは、要素の元の参照を保持します。

次に、これら2つを個別に説明します。


まず、Personプロパティを持つNameクラスを作成します。

_class Person
{
    public string Name {get; set;}
}
_

次に、Main()メソッドで、Person配列を作成します。

_// Create 2 Persons.
var person1 = new Person(){ Name = "Jack" };
var person2 = new Person(){ Name = "Amy" };

// Create a Person array.
var arrPerson = new Person[] { person1, person2 };
_

1。浅いコピーは要素をコピーします。

浅いコピーの最初の要素をreplaceする場合、元の配列は影響を受けません。

_// Create a shallow copy.
var arrPersonClone = (Person[]) arrPerson.Clone();

// Replace an element in the shallow copy.
arrPersonClone[0] = new Person(){Name = "Peter"};

// Display the contents of all arrays.
Console.WriteLine( "After replacing the first element in the Shallow Copy" );
Console.WriteLine( $"The Original Array: {arrPerson[0].Name}, {arrPerson[1].Name}" );
Console.WriteLine( $"The Shallow Copy: {arrPersonClone[0].Name}, {arrPersonClone[1].Name}" );
_

結果:

_The Original Array: Jack, Amy
The Shallow Copy: Peter, Amy
_

2。浅いコピーは、要素の元の参照を保持します。

浅いコピーの要素のプロパティをchangeすると、この要素が参照するオブジェクトはコピーされないため、元の配列が影響を受けます。

_// Create a new shallow copy.
arrPersonClone = (Person[]) arrPerson.Clone();

// Change the name of the first person in the shallow copy.
arrPersonClone[0].Name = "Peter";

// Display the contents of all arrays.
Console.WriteLine( "After changing the Name property of the first element in the Shallow Copy" );
Console.WriteLine( $"The Original Array: {arrPerson[0].Name}, {arrPerson[1].Name}" );
Console.WriteLine( $"The Shallow Copy: {arrPersonClone[0].Name}, {arrPersonClone[1].Name}" );
_

結果:

_The Original Array: Peter, Amy
The Shallow Copy: Peter, Amy
_

では、単純な等号_=_はどのように動作しますか?

参照コピーを作成します。要素または参照オブジェクトへの変更は、元の配列と「コピーされた」配列の両方に反映されます。

_// Create a reference copy.
var arrPersonR = arrPerson;

// Change the name of the first person.
arrPersonR[0].Name = "NameChanged";
// Replace the second person.
arrPersonR[1] = new Person(){ Name = "PersonChanged" };

// Display the contents of all arrays.
Console.WriteLine( "After changing the reference copy:" );
Console.WriteLine( $"The Original Array: {arrPerson[0].Name}, {arrPerson[1].Name}" );
Console.WriteLine( $"The Reference Copy: {arrPersonR[0].Name}, {arrPersonR[1].Name}" );
_

結果:

_The Original Array: NameChanged, PersonChanged
The Reference Copy: NameChanged, PersonChanged
_

結論として、_ob2 = ob1_は浅いコピーではなく、参照コピーです。

遊ぶための完全なコード:

_void Main()
{
    // Create 2 Persons.
    var person1 = new Person(){ Name = "Jack" };
    var person2 = new Person(){ Name = "Amy" };

    // Create a Person array.
    var arrPerson = new Person[] { person1, person2 };

    // ----------- 1. A shallow copy copies elements. -----------

    // Create a shallow copy.
    var arrPersonClone = (Person[]) arrPerson.Clone();

    // Replace an element in the shallow copy.
    arrPersonClone[0] = new Person(){Name = "Peter"};

    // Display the contents of all arrays.
    Console.WriteLine( "After replacing the first element in the Shallow Copy:" );
    Console.WriteLine( $"The Original Array: {arrPerson[0].Name}, {arrPerson[1].Name}" );
    Console.WriteLine( $"The Shallow Copy: {arrPersonClone[0].Name}, {arrPersonClone[1].Name}" );

    Console.WriteLine( "\n" );

    // ----------- 2. A shallow copy retains the original references of the elements. -----------

    // Create a new shallow copy.
    arrPersonClone = (Person[]) arrPerson.Clone();

    // Change the name of the first person in the shallow copy.
    arrPersonClone[0].Name = "Peter";

    // Display the contents of all arrays.
    Console.WriteLine( "After changing the Name property of the first element in the Shallow Copy:" );
    Console.WriteLine( $"The Original Array: {arrPerson[0].Name}, {arrPerson[1].Name}" );
    Console.WriteLine( $"The Shallow Copy: {arrPersonClone[0].Name}, {arrPersonClone[1].Name}" );

    Console.WriteLine( "\n" );  

    // ----------- 2. The equal sign. -----------

    // Create a reference copy.
    var arrPersonR = arrPerson;

    // Change the name of the first person.
    arrPersonR[0].Name = "NameChanged";
    // Replace the second person.
    arrPersonR[1] = new Person(){ Name = "PersonChanged" };

    // Display the contents of all arrays.
    Console.WriteLine( "After changing the reference copy:" );
    Console.WriteLine( $"The Original Array: {arrPerson[0].Name}, {arrPerson[1].Name}" );
    Console.WriteLine( $"The Reference Copy: {arrPersonR[0].Name}, {arrPersonR[1].Name}" );
}

class Person
{
    public string Name {get; set;}
}
_
1
Anthony

2番目のオブジェクトに割り当てた後、最初のオブジェクトのプロパティを変更するには、さらに2、3行のコードを記述します。次に、両方のオブジェクトでdisplayメソッドを呼び出して、結果を確認します。これにより、実際には浅いコピーであることがわかります。

0