How to copy link types (deepcopy)?
I have a constructor on a collection that takes an IEnumerable. I want to enumerate and create a new collection using elements, but not refer to the same elements. Elements can be values and reference types:
CustomCollection cc = new CustomCollection (IEnumerable<T> items)
{
foreach (var item in items)
{
this.Add(item); // justs adds the reference for ref types.
}
}
EDIT: .NET collections have the same methods and don't do deep copy. Why would you want to have a collection that references the same items as the original one?
a source to share
If the classes in question support serialization, you can serialize the collection to a temporary stream and deserialize them back to the new collection.
Some classes support ICloneable, but exactly what it does is left to the programmer to decide. It might be a deep copy, it might not.
Of course, not all classes support serialization and cloning, so what you want cannot be done for all types.
To do this, you need to set some restrictions.
a source to share
If the objects are serializable, you can make deep copies like this:
private object GetCopy(object original)
{
if (original == null)
{
return null;
}
object result;
using (MemoryStream stream = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, original);
stream.Position = 0;
result = formatter.Deserialize(stream);
stream.Close();
}
return result;
}
a source to share
The effects of a deep copy vary greatly, so deep copies are not automatically provided by the CLR. Imagine, for example, what would happen if your duplicated deep copy objects were stored in OS managed resources (e.g. SQL connections, sockets, custom GDI brushes, etc.).
You really need to stick to a method like the one suggested above. Make sure T is ICloneable if you believe you trust the sources to properly implement the interface. If not (either trust the source, or if T is not cloned), check if the object is marked ISerializable or has SerializableAttribute and then serialized / deserialized into a new object.
If T is not clonable or serializable, then you should probably throw an exception and not try to make a deep copy.
a source to share
I don't know the syntax as I haven't worked with it much, but couldn't this be done with Reflection? I understand that reflection usually leads to a performance hit, but you can do something like a switch code thing, something like the following:
(pseudocode)
if(item.isValueType) {
newCol.Add(item)
} elseif(item.isRefType && item.SupportsICloneable) {
newCol.Add(item.clone())
} else {
doReflectionCopy()
}
You can also add code for serializable validation and include Frederick's method.
a source to share