DeepCloner icon indicating copy to clipboard operation
DeepCloner copied to clipboard

Mix of deep and shallow copy

Open mrinalkamboj opened this issue 7 years ago • 7 comments

Is there a provision in the library to make shallow copy of few expensive objects, while we deep copy the remaining object graph. I doubt on reviewing the APIs, I do plan to make code change, by supplying an explicit Dictionary with expensive objects added to it and in case object is there in the dictionary then create a Shallow version else a regular code which creates a deep version. Please suggest if my understanding is correct and may be some guidance to make code modification.

To provide more clarity:

My object is of following type, where both ODPair and ServiceProduct are the custom types. ServiceProduct is an expensive object, for which I want to retain the Shallow copy, while rest of the object is deep copied

Dictionary<ODPair,Dictionary<string,List<ServiceProduct>>>

mrinalkamboj avatar Dec 26 '17 10:12 mrinalkamboj

There is no public api to do this. But if you want to override current implementation, you can see to DeepClonerSafeTypes class, there are two corresponding methods:

  • CanNotCopyType - do not copy type if it safe to use same instance for cloned objects (e.g. strings, structs, primitive types or some internal .NET objects)
  • CanNotDeepCopyClass - do not deep copy class it in considered to be safe for safe cloning (no references to other types, e.g. simple dto object).

You can override implementation of both methods (by the request, CanNotDeepCopyClass looks more appropriate) to reduce deep copying of object.

force-net avatar Dec 26 '17 19:12 force-net

Thanks, I exposed a Helper class with method to add a specific Type like ServiceProduct to KnownTypes dictionary for shallow cloning and it does work as expected, however in this case I still cannot have object level control, since whole type will always be Shallow cloned, is there a way to make it object level control, where specific objects are only shallow cloned, not a given Type. this would be fine grain control. I was trying to figure out in code where does it consider the object hierarchy for cloning the aggregations and compositions, but was unsure. Can you please provide more information.

mrinalkamboj avatar Dec 27 '17 07:12 mrinalkamboj

It seems, there are no good ability to do that. Current implementation do object cloning recursively but each object is independent and use same code for cloning. You can look at DeepClonerGenerator, CloneClassRoot method to determine initial object and CloneClassInternal for cloning dependent objects. DeepCloneState can be used for some meta info.

force-net avatar Dec 27 '17 07:12 force-net

One issue with deep cloning is that HashSets of objects whose hash codes are generated by reference (the default) will be copied with the persisted hash codes representing the original objects, not the newly cloned ones (likewise for Dictionaries). This can cause unexpected behaviour, e.g. HashSet.Contains will return false when it actually does contain the provided object.

This does limit the usefulness of blindly cloning a deep, complex object structure. It would be nice if there was a way to specify object types that we don't want to deep clone via reflection and potentially could provide delegates to perform the clone for these types instead.

e.g.

myObject.DeepClone(
    new Dictionary<Type, Func<object, object>>
    {
        { typeof(HashSet<>), hashSet => "do something smart" }
    }
);

As per mrinalkamboj's use case, this could be per object rather than per type.

Alternatively, the framework could just treat HashSets & Dictionaries (and any other Hash based collections) as special cases: e.g. emit a constructor for the relevant generic type and then iterate through the collection calling Add for each cloned element. This would be preferable for my use case, and should still be super fast

jamesrokt avatar Oct 19 '18 11:10 jamesrokt

Thanks. It is interesting issue. It is bad idea to store objects without GetHashCode implementation due undefined behavior for such operations, but it possible, so, some solution should be provided by DeepCloner.

I'll think about better solution to do this, because simple specific method for HashSets and Dictionaries can be problematic due lot of types of such collections and ability to specify there custom equality comparers. Custom options for cloning types/objects can be useful. I'll think about best solution to do this.

force-net avatar Oct 22 '18 07:10 force-net

Did this issue with cloning HashSet (containing objects without GetHashCode implementation) get solved ?

Uptixs avatar May 02 '19 21:05 Uptixs

No. Sorry.

force-net avatar May 03 '19 15:05 force-net