0

I am doing a custom dictionary key solution similar to whats described here: Use custom object as Dictionary Key

However in my case the key can be one of 2 objects in a hierarchy. I am getting the key not found exception when perfomring somethin like this:

foreach (IntPointMutable key in tmxMapOffsets.Keys)
{
     newTmxMapOffsets[new IntPoint(key.X - minXValue, key.Y + minYValue)] = tmxMapOffsets[key];
}

I considered the following scenarios for my 2 classes: IntPoint and IntPointMutable. They simply are 2 ints, X and Y wrapped in an object much like a vector2 is for floats.

  • IntPoint may be compared to an IntPoint
  • IntPoint may be compared to an IntPointMutable
  • IntPointMutable may be compared to an IntPoint
  • IntPointMutable may be compared to an IntPointMutable

I created a simple GetHashCode implementation that for my needs will produce all unique results(granted its not going to work if you had large values)

public override int GetHashCode()
{
    return x * 10000 + y;
}

I then implemented in IntPoint the following things

public class IntPoint:Object,IEquatable<IntPoint>,IEquatable<IntPointMutable>

public override bool Equals(Object obj)
{
    if (obj == null)
    {
        return false;
    }
    return (obj.GetType() == typeof(IntPoint) || obj.GetType() == typeof(IntPointMutable)) && (IntPoint)obj == this;
}

public bool Equals(IntPointMutable obj)
{
    if (obj == null)
    {
        return false;
    }
    return (IntPoint)obj == this;
}

public bool Equals(IntPoint obj)
{
    if (obj == null)
    {
        return false;
    }
    return obj.GetType() == typeof(IntPoint) && (IntPoint)obj == this;
}

So it seems like I have all my bases covered but yet it cannot do a dictionary lookup where one object of each type is involved. Also I dislike that I had to put knowledge of a subclass in its parent, but I wasn't sure how to allow an IntPoint.Equals(someIntPointMutable) situation to work otherwise.

Any ideas?

And also I overrode the == operator so that the comparison would work above

public static bool operator ==(IntPoint a, IntPoint b)
{
    if (System.Object.ReferenceEquals(a, b))
    {
        return true;
    }

    if((object)a == null ||(object)b == null)
    {
        return false;
    }

    // Return true if the fields match:
    return a.X == b.X && a.Y == b.Y;
}

Some updates after the various comments:

It apparently should work fine without knowing about the mutable version in the superclass as far as comparison checks go, so I will remove that. Also the mutable one was being stored into the dictionary which is a no-no so I changed that. Ideally I get rid of the mutable version to avoid this happening accidently. is the best bet to use a struct or something to replace this as an easy way to pass around a pair of ints thats more clear then just an int[]?

Cœur
  • 37,241
  • 25
  • 195
  • 267
user2292539
  • 245
  • 1
  • 11
  • 1
    Have you overloaded `==`? If not, your `return (IntPoint)obj == this;` isn't going to work. – Jon Skeet Mar 03 '14 at 20:03
  • examples of what isnt' working... doesn't work ever? – T McKeown Mar 03 '14 at 20:03
  • I just added that bit to the post – user2292539 Mar 03 '14 at 20:03
  • 1
    (As a general point, using mutable keys is a generally bad idea. Do you really *have* to have the `IntPointMutable` class at all?) – Jon Skeet Mar 03 '14 at 20:03
  • If `IntPointMutable` is a subclass of `IntPoint`, than `IntPoint` should have no knowledge of it. And you wouldn't need to cast an `IntPoint` into a `IntPointMutable`. Can you post the code using the dictionary? – Paulo Morgado Mar 03 '14 at 20:05
  • Thats a very good point... I did this because I didnt want to have to create tons of throw away objects when doing a long loop of operations on these points. But I see that it might cause me problems down the road. Perhaps the problem is the value was put into the table and then changed afterwords but still remains in the wrong hash slot? – user2292539 Mar 03 '14 at 20:07
  • I posted the code using the dictionary – user2292539 Mar 03 '14 at 20:07

1 Answers1

1

What about implementing IntPoint as an immutable value type (if, indeed it contains no more than few fields), and discard MurableIntPoint?

Shlomi Borovitz
  • 1,700
  • 9
  • 9
  • IntPoint is already immutable. What are the pros to having be a struct intstead of an object? My main concern was some 2d for loop itterating across a large 2d array wanting to do something with a point in each loop itteration. if it has to allocate memory each time, thats not desirable. Will a struct use the same memory like it does in old c if I assign it new values? – user2292539 Mar 03 '14 at 20:40
  • Struct IS an object. Anyway, if I understand correctly - you implemented the mutable type to save memory allocations, and if that the case (and if it's indeed small type, and, you don't need inheritance for it) value type would save those allocations, without implications – Shlomi Borovitz Mar 03 '14 at 20:44
  • My apologies for not reading your entire comment, but I happy that I did understood you :-) – Shlomi Borovitz Mar 03 '14 at 21:20
  • Thanks I believe this is the best way to go – user2292539 Mar 03 '14 at 21:21