Giter Club home page Giter Club logo

Comments (8)

force-net avatar force-net commented on July 19, 2024 2

This is complex issue, related to missing GetHashCode implementation for object. Without implementation β€” object reference is used. So, after cloning clonedObject has another reference and GetHashCode for it returns another value.
In real situation correct implementation of GetHashCode is very recommended. I'll think about possible variants of mitigation of this problem.

from deepcloner.

zane-woodard-drc avatar zane-woodard-drc commented on July 19, 2024

Ran into this issue after switching to DeepCloner from BinaryFormatter. BinaryFormatter had the same fundamental issue, but I was able to work around it by using the [OnDeserialized] hook like this:

public class MyObject<T> : IList<T>
{
    private HashSet<T> _uniqueItemTracker = new HashSet<T>();

    //Omitting IList<T> implementation

    [OnDeserialized]
    private void OnDeserialized(StreamingContext context)
    {
        //After cloning, OnDeserialized invoked and the _uniqueItemTracker is re-populated by creating a new HashSet off the current contents
        _uniqueItemTracker = new HashSet<T>(this);
    }
}

This doesn't solve the fundamental problem, but a post-DeepClone hook would at least allow us to write code to fix it ourselves.

from deepcloner.

force-net avatar force-net commented on July 19, 2024

Currently, I'm trying to find best solution to mitigate this issue.
E.g. this code will not work by design (we clone set entirely but check with non-cloned object).

var key = new object();
var set = new HashSet<object> {key};
var cloned = set.DeepClone();
Assert.That(cloned.Contains(key)); // failed

This case can occur in any complex cloning and cannot be solved without custom handlers.

For you case, you can wrap set with new set, but EqualityComparer can be passed to HashSet (so, we need to pass it to new Set). Also, there are a lot of Dictionaries and Sets implementations with custom behavior, so, it hard to make correct general cloning.

from deepcloner.

cguedel avatar cguedel commented on July 19, 2024

Is there any update on this? There's some weird things going on with strings as well.

Note that this only fails on .net 6.0 and passes on netcoreapp3.1. It could probably have something to do with an optimization in HashSet for when T == typeof(string).

var set = new HashSet<string> { "value" };
set.Contains("value").Should().BeTrue(); // pass

var cloned = set.DeepClone();
cloned.Contains("value").Should().BeTrue(); // pass

var copyOfSet = new HashSet<string>(set, set.Comparer);
copyOfSet.Contains("value").Should().BeTrue(); // pass

var copyOfCloned = new HashSet<string>(cloned, cloned.Comparer);
(copyOfCloned.ToArray()[0] == "value").Should().BeTrue(); // pass

copyOfCloned.Contains("value").Should().BeTrue(); // fail

from deepcloner.

cguedel avatar cguedel commented on July 19, 2024

If I hack together a separate processing method for HashSet, where I just return new HashSet<string>(objFrom, objFrom.Comparer), this test works. so it's probably only related to strings...

from deepcloner.

force-net avatar force-net commented on July 19, 2024

It's really strange, but interesting issue.
When HashSet created it checks:

  1. is comparers are same (for strings it should be true, but there are lot of internal magic to create Comparer.Default) - in this case it just copies internal HashSet objects
  2. if it differs code like to new HashSet(comparer).UnionWith(source.AsEnumerable())

In both cases result should be identical. So, I'll try to reproduce problem and found a source of this issue.

from deepcloner.

force-net avatar force-net commented on July 19, 2024

I found an issue and fix it (will do some more tests and will publish new version in some days).
Problem only with strings (but another code can also cause similar problems).
HashSet in .NET6.0 uses special comparer for strings if no specific comparer is provided. Also, it returns non-real Comparer when you ask for it (it uses NonRandomizedStringEqualityComparer but returns GenericEqualityComparer).
When you create new instance of HashSet, it checks comparer == EqualityComparer<string>.Default - and it fails for cloned comparer. So, HashSet began to use GenericEqualityComparer instead of default and it produces different hash code
So, it real .NET magic and it needs to be analyzed.

from deepcloner.

cguedel avatar cguedel commented on July 19, 2024

Yeah I saw that too, not sure what's exactly going on there. Looking forward to a new release. I've tested a workaround where in the deep cloner code I detect instances of HashSet and simply use a new HashSet<string>(source, source.Comparer) to create the clone, this seems to work pretty good.

from deepcloner.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.