2

I have two classes. In one is nested another class.

class Person : ICloneable
{
    public string name;
    public City city;

    public object Clone()
    {
        return this.MemberwiseClone();
    }
}

class City
{
    public string name;

    public City( string _n)
    {
        name = _n;
    }
}

In Person class is clone method to make shallow copy. When I made clone of class Person, I got clone of class Person and clone of nested class City.

        Person person = new Person()
        {
            name = "John",
            city = new City("London")
        };

        Person personNew = (Person)person.Clone();

        Console.WriteLine( $"{personNew.name}\t\n{personNew.city.name}");

Result:
John
London

I expected to get value of City class as null because I made shallow copy of Person class but it looks like deep copy. Why ?

Rafal
  • 21
  • 1
  • 2
  • There is still one `City` object, and both your `Person` objects are referencing that same object. A deep clone would result in the `City` object also being copied. – Johnathan Barclay Dec 21 '19 at 09:26

2 Answers2

2

No, it is not a DeepCopy, to understand what's happening try to add this code after yours

personNew.name = "Steve";
personNew.city.name = "Paris";

// Print out the values of the original person
Console.WriteLine($"{person.name}\t\n{person.city.name}");

Result:

John  
Paris

So you changed the city name in newPerson but this affects the city in person as well. This happen because they are the same instance of the City class. And this is what MemberwiseClone does. It copies the field values but doesn't create new objects instances. And in case of reference types the field value is the reference to the object instance, not the instance itself.

If you want to execute a DeepCopy then you need first add the [Serializable] attribute to your classes

[Serializable]
class Person
....
[Serializable]
class City

and then change the Clone method to

public object Clone()
{
    using (MemoryStream stream = new MemoryStream())
    {
        if (this.GetType().IsSerializable)
        {
            BinaryFormatter fmt = new BinaryFormatter();
            fmt.Serialize(stream, this);
            stream.Position = 0;
            return fmt.Deserialize(stream);
        }
        return null;
    }
}

You can find a better examples for a DeepCopy approach in this answer:

Deep cloning objects

Steve
  • 213,761
  • 22
  • 232
  • 286
1

You have just copied with shallow copy, it's right. Of course, It copy all properties of person instance. Why do you think city is an exception and dont be copied? And if you want to excute deep copy, try this:

Person class:

    class Person : ICloneable
    {
        public string name;
        public City city;

        public object Clone()
        {
            return this.MemberwiseClone();
        }
        public Person DeepCopyAndDisposeCity()
        {
            return new Person()
            {
                name = this.name,
                city = null
            };
        }
    }

Program:

            Person person = new Person()
            {
                name = "John",
                city = new City("London")
            };

            Person personNew = person.DeepCopyAndDisposeCity(); //(Person)person.Clone();
            //personNew.city = new City( "Hanoi");
            string cityOfNewPersion= personNew.city == null ? "null" : personNew.city.name;

            Console.WriteLine("Person:");
            Console.WriteLine($"{person.name}\t\n{person.city.name}");
            Console.WriteLine("New Person:");
            Console.WriteLine($"{personNew.name}\t\n{cityOfNewPersion}");
            Console.ReadKey();
Nguyen Van Thanh
  • 805
  • 9
  • 18