It’s not true exactly. Of course there’s a way, it’s just different.
Ready-made solution
Every object in C# derives from the class Object
which has a method called MemberwiseClone()
which can only be accessed within the class (is protected). It makes the blank copy of all members of the object, as you wish.
But note that it does not make the deep copy. That is. It copies everything in the object, bit by bit, but does not create new objects for the references of that object. It does with members the same as the last examples of the question. It copies the references to the new object, but they point to the same objects that the original point to.
So in a shallow copy what modifies in this object does not affect the original object, after all they are very different thing. But if you modify the objects referenced within your object these modifications will be reflected in the original object, since the reference is the same in these objects.
If it’s hard to understand, you need to understand difference between types by value and types by reference. And about immutability.
I talk about it in a PHP question. In general it is more or less the same thing.
There is an example making the deep copy on documentation of MemberwiseClone()
.
Customized solution
Classes that want to be copied need a method Clone()
. This is different from C++ that provides a copy constructor whenever the programmer explicitly prevents it. The copy is normal np C++. In C# it is possible.
The cloning method is only available in the classes that implement the interface IClonable
.
In it you can create a shallow or deep copy. It is the decision of the programmer to decide how cloning should proceed. Each class must decide whether to do it this way or not, just as in C++, but in C++ if it does not create anything custom, the copy is shallow. In C# if you want to make only the single copy you need to call MemberwiseClone()
within the Clone()
, nothing more.
When you use the IClonable
any operation that requires cloning can receive this object without knowing what it does.
Deep copy
It is common to make the deep copy, but nothing obliges it to be so. The documentation does not determine what the Clone()
should do. Can make shallow, deep copy, or a middle ground. It doesn’t even need to make a complete blank copy, it could just be a selection of members, if it makes sense.
If you decide to make the deep copy method Clone()
should create new objects referenced by members and copy their contents to the new reference, probably called the method Clone()
of each of them. That is, does what the AP did in the first examples of the question.
If your class’s member objects have methods Clone()
that make deep copy, goes firing the copy tree. Hope not to have cyclic reference and not end more (has solution, of course).
Of course cloning is not the only option, there are other ways to copy these objects. An option, if available, is just to create a new object by passing the members of the original as arguments in the constructor, or you can pass the original object as argument. There is a lot of class that does this. It is a way to have a copy constructor equal to C++. In this constructor he reads all members and copies their members properly. Of course, those who consume this, need to know that there is this possibility, is not standardized as cloning "official".
Some cloning is very complex and can go far beyond just copying memory.
It is common for people to have an extension method that makes a deep copy and implements the interface method implicitly.
Non-standard
Some objects may have specific methods to make copies in a specific way. Here it goes to each one. You have to see the class documentation. It cannot be used in a standardized way as the MemberwiseClone()
and the Clone()
. An example is the Array.Copy()
. It is also common to implement a specialized version of Clone()
returning the class type object. The implementation of IClonable
must return a object
, which may require a cast in their use.
In theory it is possible to clone even what is not prepared to do so. But it is complicated. You have to resort to reflection to ensure that everything that is needed will be done, you have to access internal things that are implementation details and nothing guarantees that this will always work.
Serialization is an option.
Note that it is not so common to use this interface in C#. It is rare to use copy of the content since it can be expensive and almost always not the desired semantics. Hence the existence of more specific methods when it makes sense. C++ itself has preferred to move rather than copy.
Completion
The theme is extensive, theme enough thing to learn about it, has a lot of problematic situation.
I made an example with two forms of cloning.
Behold working in the ideone. And in the .NET Fiddle. Also put on the Github for future reference.
This description uses the term "reference" wrongly applied to the language C++. Where "reference" is read "pointer". In C++ reference has another technical meaning.
– zentrunix