Reputation: 11515
What is the best way to deep clone an interconnected set of objects? Example:
class A {
B theB; // optional
// ...
}
class B {
A theA; // optional
// ...
}
class Container {
A[] a;
B[] b;
}
The obvious thing to do is walk the objects and deep clone everything as I come to it. This creates a problem however -- if I clone an A
that contains a B
, and that B
is also in the Container
, that B
will be cloned twice after I clone the Container
.
The next logical step is to create a Dictionary
and look up every object before I clone it. This seems like it could be a slow and ungraceful solution, however.
Any thoughts?
Upvotes: 5
Views: 1992
Reputation: 10249
The dictionary solution you suggested is the best I know of. To optimize further, you could use object.GetHashCode()
to get a hash for the object, and use that as the dictionary key. Should be fast unless you're talking about huge object trees (10s to 100s of thousands of objects).
Upvotes: 2
Reputation: 15179
One of the practical ways to do deep cloning is serializing and then deserializing a source graph. Some serializers in .NET like DataContractSerializer
are even capable of processing cycles within graphs. You can choose which serializer is the best choice for your scenario by looking at the feature comparison chart.
Upvotes: 0
Reputation: 755491
Another possible solution you could investigate is serializing the objects into a stream, and then reconstructing them from that same stream into new instances. This often works wonders when everything else seems awfully convoluted and messy.
Marc
Upvotes: 0
Reputation: 18181
maybe create a bit flag to indicate whether this object has been cloned before.
Upvotes: 0
Reputation: 12975
Its not an elegant solution for sure, but it isn't uncommon to use a dictionary (or hashmap). One of the benefits is that a hashmap has a constant lookup time, so speed does not really suffer here.
Upvotes: 2
Reputation: 24282
Not that I am familiar with C#, but typically any type of crawling of a graph for some sort of processing will require a lookup table to stop processing an object due to cyclic references. So I would think you will need to do the same here.
Upvotes: 2