I am reading the book "Dingle, A. (2021). Chapter: Cloning in C#. In Object-oriented design choices (pp. 71–73), CRC Press." and in the chapter about Cloning in C# it shows how to make a deep and a shallow copy of an object through the UCopy
class.
I am having trouble understanding how all this works. I found some blogs online and it says a true deep copy is hard to make in C# (without the Serialize and Deserialize method). I am working on implementing this in my assignment and I can't wrap my head around the process.
UCopy
class for every class I make (Is it made to copy one class only, or should it be generic)u4
is not a true deep copy because, as in u3
, the AnotherClass object is distinct, but the Own
value is not truly distinct as it's initialized from the same static id
.Clone
method come in?Here is the code example from the book (FIGURE 3.5)
public class AnotherClass
{
private static uint id = 1000;
private readonly uint own;
public AnotherClass()
{
own = id++;
}
public uint Own => own;
}
public class UCopy
{
private AnotherClass address;
public UCopy()
{
address = new AnotherClass();
}
// Deep copy: heap memory allocated for a true copy
public UCopy DeepCopy()
{
// Internal cast
UCopy local = (UCopy)this.MemberwiseClone();
local.address = new AnotherClass();
return local;
}
// Shallow copy: distinct objects have the same address
public UCopy ShallowCopy()
{
return (UCopy)this.MemberwiseClone();
}
}
public class Program
{
public static void Main()
{
// Client code
// #1: UCopy object allocated
UCopy u1 = new UCopy();
// Embedded 'Own' id of 1000
// #2: Shallow copy, aliased with u1
UCopy u2 = u1.ShallowCopy();
// Embedded 'Own' id of 1000
// #3: Shallow copy, aliased with u1
UCopy u3 = u1.DeepCopy();
// Embedded 'Own' id of 1000
// #4: Deep copy - DISTINCT object
UCopy u4 = u1.DeepCopy();
// Embedded 'Own' id of 1001
}
}
You run down a deep rabbit hole if use MemberwiseClone()
as it really doesn't make it clear what you need to modify to make a deep clone.
You're better off writing our own deep clone method and explicitly update everything.
Here's an example:
public class Class1
{
public Class2 Class2 { get; init; }
public string Id { get; set; }
public Class1 DeepCopy() => new Class1()
{
Id = this.Id,
Class2 = this.Class2.DeepCopy()
};
}
public class Class2
{
public Class3 Class3 { get; init; }
public string Id { get; set; }
public Class2 DeepCopy() => new Class2()
{
Id = this.Id,
Class3 = this.Class3.DeepCopy()
};
}
public class Class3
{
public string Id { get; set; }
public Class3 DeepCopy() => new Class3()
{
Id = this.Id
};
}
I think you're better off, though, writing static method on each class to do the cloning:
public class Class1
{
public Class2 Class2 { get; init; }
public string Id { get; init; }
public static Class1 DeepClone(Class1 clone) => new Class1()
{
Id = clone.Id,
Class2 = Class2.DeepClone(clone.Class2)
};
}
public class Class2
{
public Class3 Class3 { get; init; }
public string Id { get; init; }
public static Class2 DeepClone(Class2 clone) => new Class2()
{
Id = clone.Id,
Class3 = Class3.DeepClone(clone.Class3)
};
}
public class Class3
{
public string Id { get; init; }
public static Class3 DeepClone(Class3 clone)
=> new Class3() { Id = clone.Id };
}
Then you'd write close like this:
Class1 object1 = new Class1()
{
Id = "C1",
Class2 = new Class2()
{
Id = "C2",
Class3 = new Class3()
{
Id = "C3",
}
}
};
Class1 object1c = Class1.DeepClone(object1);
In either case, you're 100% in control of the deep cloning process and it's explicit what you're doing.