Question

I have a dictionary where the keys are XYZ objects and the values are boolean. The XYZ class is from Autodesks API, so its not a class I made. I am attempting to check if a key exists in the dictionary.

My Problem: If the dictionary contains the key new XYZ(1,1,1) and I go to check if the dictionary contains this key using myDictionary.ContainsKey(new XYZ(1,1,1) is always returns false.

Why is this happening and how can I fix this? I think that the class XYZ needs its Equals method implemented but as I mentioned before I didn't make this class, its part of Autodesks API. Or am I doing something wrong?

Dictionary<XYZ, bool> prevPnts = new Dictionary<XYZ, bool>();
prevPnts[new XYZ(1,1,1)] = true;

// Always says the pnt doesnt exist?
if (prevPnts.ContainsKey(new XYZ(1,1,1)))
   TaskDialog.Show("Contains");
else TaskDialog.Show("NOT Contains");

Solution using Konrads answer

class XYZEqualityComparer : IEqualityComparer<XYZ>
{
    public bool Equals(XYZ a, XYZ b)
    {
        if (Math.Abs(a.DistanceTo(b)) <= 0.05)
            return true;

        return false;
    }


    public int GetHashCode(XYZ x)
    {
        int hash = 17;
        hash = hash * 23 + x.X.GetHashCode();
        hash = hash * 23 + x.Y.GetHashCode();
        hash = hash * 23 + x.Z.GetHashCode();
        return hash;
    }
}

Dictionary<XYZ, bool> prevPnts = new Dictionary<XYZ, bool>(new XYZEqualityComparer());
Was it helpful?

Solution

Provide your own IEqualityComparer to the dictionary, as it does not know how to compare XYZ class (strictly speaking, it compares them by reference):

class XYZEqualityComparer : IEqualityComparer<XYZ>
{
    public bool Equals(XYZ a, XYZ b)
    {
        return a.X == b.X && a.Y == b.Y && a.Z == b.Z;            
    }    

    public int GetHashCode(XYZ x)
    {
        int hash = x.X ^ x.Y ^ x.Z;
        return hash .GetHashCode();
    }
}

and then:

Dictionary<XYZ, bool> prevPnts = new Dictionary<XYZ, bool>(new XYZEqualityComparer());

Note: My implementation of GetHashCode is only exemplary. Read What is the best algorithm for an overridden System.Object.GetHashCode? for better alternatives.

OTHER TIPS

For classes that do not override the Equals and GetHashCode methods, the comparison algorithm will default to reference equality rather than value equality. Thus, although the values for the value fields/properties of the class instance might be the same, the instance itself is different, thus the equality fails.

In this case, you basically cannot use this class as a key in a dictionary by itself, unless you define an IEqualityComparer<XYZ> implementation for this class. Take a look at this answer by @Konrad Kokosa

As you correctly observed, if the Equals and GetHashCode methods have not been implemented by the XYZ class then it will do a reference comparison (only true if they reference the same object on the heap).

One resolution to this since you don't have access to the class is wrap it in your own class, where you can write a Equals method that uses the contents of XYZ to do a proper comparison.

class WrapperXYZ
{
    XYZ xyz;

    public override bool Equals(object other)
    {
        if(other is typeof(XYZ))
        {
            // check the contents
        }
        else
        {
            return false;
        }
    }

    // TODO: write a hash method if you are using a dictionary
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top