What you're referring to is called
cloning. There are few things to it.
First, if you simply copy an instance of one reference type to another instance, you have the reference to the same object, but if you copy an instance of value object you always got a
shallow copy of the original object. If all instance members of the structure are also value objects and those value objects also have only value-type members, and so on, to the very bottom if it, you always have a full clone, but is a reference-type member is involved, you have a shallow copy: the reference-type components are not cloned but share the same references.
There is no one universal method of making a full clone of all members, recursively. One reason for that is that the infinite recursion should be avoided. The way to solve this problem is providing the custom cloning in your code.
The interface
System.IsClonable
is available exactly for this purpose. You can implement it for any type you want to clone (it could be a value type as well, a structure). You implement
System.IsClonable.Clone
and provide per-member cloning, re-creating and cloning each member (but perhaps not every one; it depends on your semantics) appropriately.
It does not guarantee full recursive cloning, as every member type can be a structure or a class encapsulating a mixture of reference and value type. These type may or may not implement the interface
System.IsClonable
. This is only a tool to guarantee custom cloning which may or may not be recursively complete.
However, I used to provide automatic fully automated recursive cloning as well. To do that, I introduced analogous interface
IDeeplyClonable
with default implementation based on Reflection. This implementation analyzes all members of the type and see if some of them of 1) value types, 2) implement
IDeeplyClonable
, 3) implement
IClonable
; depending on that, either a shallow copy or a method
Clone
is invoked for cloning a member. This approach should be used with care. It should guarantee recursive cloning does not go into infinite recursion; also it can be relatively slow.
There is one more exotic but comprehensive way to provide semantically complete cloning. Is is based on serialization, in particular in
Data Contract. The cloning semantic will be based on
DataContract
/
DataMember
attributes applied to all types and members involved. The problem of infinite recursion can be solved automatically — this method allows persisting object graph even if it is not a tree (that is, even if it contains loops). This method is also the least intrusive (you only add attributes, do not touch and existing declarations). One can persist an object graph to memory stream (for example) and read id into another object which becomes and exact clone semantically fully equivalent to the original one. For big objects or object graphs, performance can be some minor problem, but it can be considered as a fair price for extreme consistency and robustness.
For further detail, see:
http://msdn.microsoft.com/en-us/library/system.runtime.serialization.datacontractserializer.aspx[
^],
http://msdn.microsoft.com/en-us/library/system.runtime.serialization.datacontractattribute.aspx[
^],
http://msdn.microsoft.com/en-us/library/system.runtime.serialization.datamemberattribute.aspx[
^].
For overview, see
http://msdn.microsoft.com/en-us/library/ms733127.aspx[
^], only remember that your goal is not persistence per se, but in this case just deep cloning.
—SA