2

I want to create a Dictionary<Coordinate, Status>, but the key is always equals to "Bot.Core.Games.Coordinate".

Classes

Coordinate

public class Coordinate
{
    public int x { get; set; }
    public int y { get; set; }
}

Status

public class Enums
{
    public enum Status { UNCAPTURED, PLAYER1, PLAYER2, WIN }
}

First try

Dictionary<Coordinate, Status> Fields { get; set; } = new Dictionary<Coordinate, Status>()
{
    {new Coordinate() { x = 0, y = 0 }, Status.UNCAPTURED}
}

Second try

I did some research and I found this: Use custom object as Dictionary Key
So the code now looks like this:

public class Coordinate
{
    public int x { get; set; }
    public int y { get; set; }

    public bool Equals(Coordinate coordinate) => coordinate.x.Equals(x) && coordinate.y.Equals(y);
    public bool Equals(object o) => Equals(o as Coordinate);
    public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode();
}

Third try

Since none of the previously tried code works I did more research and found this.
So now the code is:

public class Coordinate
{
    public int x { get; set; }
    public int y { get; set; }

    public class CoordinateEqualityComparer : IEqualityComparer<Coordinate>
    {
        public bool Equals(Coordinate a, Coordinate b) => ((a.x == b.x) & (a.y == b.y));

        public int GetHashCode(Coordinate obj)
        {
            string combined = obj.x + "|" + obj.y;
            return (combined.GetHashCode());
        }
    }
}
                                                                               
Dictionary<Coordinate, Status> Fields { get; set; } = new Dictionary<Coordinate, Status>(new Coordinate.CoordinateEqualityComparer())
{
     {new Coordinate() { x = 0, y = 0 }, Status.UNCAPTURED}
}

The key is always "Bot.Core.Games.Coordinate". How to fix this?

Community
  • 1
  • 1
Noel Nemeth
  • 646
  • 11
  • 21
  • 4
    It doesn't, you are just getting confused about what the debugger tells you. Override ToString() to make it look better. – Hans Passant Jul 21 '18 at 14:05
  • @HansPassant But it also throws a KeyNotFoundException. – Noel Nemeth Jul 21 '18 at 14:13
  • 1
    Was `(a.x == b.x) & (a.y == b.y)` supposed to be `(a.x == b.x) && (a.y == b.y)`? – Camilo Terevinto Jul 21 '18 at 14:14
  • Why is `Status` inside another class (`Enums`)? – MetaColon Jul 21 '18 at 14:29
  • @Camilo Terevinto: The difference between & and && when operating on boolean operands is that && is short-circuiting while & is not (i.e., the second operand of an & operation will be evaluated even if the the first is false). Who knew!? Eric Lippert pointed this out to me about 5 years ago in a feedback comment on his blog. It's like the difference between And and AndAlso in VB. Thanks again Eric. – Flydog57 Jul 21 '18 at 19:49
  • @Flydog57 I know the difference, I was just pointing out what was likely a typo :) – Camilo Terevinto Jul 21 '18 at 19:59

2 Answers2

3

You are missing an override in your second try:

public override bool Equals(object o)

enter image description here

ZorgoZ
  • 2,974
  • 1
  • 12
  • 34
  • 1
    I doubt that was the reason the OP had problems - have a look at the comments – MetaColon Jul 21 '18 at 14:30
  • Well, just try it. I had. Without that override it throws `KeyNotFoundException`. – ZorgoZ Jul 21 '18 at 14:32
  • This answer could use a bit more explanation. No, I did not down vote. – Theraot Jul 21 '18 at 14:39
  • Thanks, now working fine, but now I can't save it into a .json file. – Noel Nemeth Jul 21 '18 at 16:04
  • 1
    True. Such keys are not json serializable. Only primitives. Remember: dictionaries and objects have the same json representations. A key has to be valid field name (identifier). But you certainly can write custom seriializer for this class as you can simply represent the coordinates in a valid identifier string. – ZorgoZ Jul 21 '18 at 20:10
2

The key is always displayed as Bot.Core.Games.Coordinate because in default, the ToString method returns the class name and this is the method the debugger calls to display its value. If you override the method like this:

public override string ToString() => $"{x} / {y}";

It will display its true value.

The problem with your third try was (as was pointed out by Camilo Terevinto and ZorgoZ) your equality comparison - try

public override bool Equals(Coordinate a, Coordinate b)
{
    return ((a.x == b.x) && (a.y == b.y));
}

instead

MetaColon
  • 2,895
  • 3
  • 16
  • 38