【问题标题】:How to use custom object as dictionary key?如何使用自定义对象作为字典键?
【发布时间】:2018-07-21 13:55:50
【问题描述】:

我想创建一个Dictionary<Coordinate, Status>,但密钥始终等于"Bot.Core.Games.Coordinate"

坐标

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

状态

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

第一次尝试

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

第二次尝试

我做了一些研究,发现了这个:Use custom object as Dictionary Key
所以代码现在看起来像这样:

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();
}

第三次尝试

由于之前尝试过的代码都不起作用,我做了更多研究,发现this
所以现在代码是:

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}
}

密钥始终是"Bot.Core.Games.Coordinate"。如何解决这个问题?

【问题讨论】:

  • 它没有,您只是对调试器告诉您的内容感到困惑。覆盖 ToString() 使其看起来更好。
  • @HansPassant 但它也会抛出 KeyNotFoundException。
  • (a.x == b.x) &amp; (a.y == b.y) 应该是 (a.x == b.x) &amp;&amp; (a.y == b.y) 吗?
  • 为什么Status 在另一个类(Enums)中?
  • @Camilo Terevinto:& 和 && 对布尔操作数进行操作时的区别在于 && 是短路的,而 & 不是(即,即使第一个是假的)。谁知道!?大约 5 年前,Eric Lippert 在他博客上的反馈评论中向我指出了这一点。这就像VB中And和AndAlso的区别。再次感谢埃里克。

标签: c#


【解决方案1】:

键总是显示为Bot.Core.Games.Coordinate,因为默认情况下,ToString 方法返回类名,这是调试器调用以显示其值的方法。如果你重写这样的方法:

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

它将显示其真实值。

您第三次尝试的问题是(正如 Camilo Terevinto 和 ZorgoZ 所指出的)您的平等比较 - 尝试

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

改为

【讨论】:

  • 这个答案也很有用。
【解决方案2】:

您在第二次尝试中缺少覆盖:

public override bool Equals(object o)

【讨论】:

  • 我怀疑这是 OP 出现问题的原因 - 看看 cmets
  • 好吧,试试吧。我有。如果没有该覆盖,它会抛出 KeyNotFoundException
  • 这个答案可能需要更多解释。不,我没有投反对票。
  • 谢谢,现在工作正常,但现在我无法将其保存到 .json 文件中。
  • 是的。这样的键不是 json 可序列化的。只有原语。请记住:字典和对象具有相同的 json 表示。键必须是有效的字段名称(标识符)。但是你当然可以为这个类编写自定义序列化器,因为你可以简单地用一个有效的标识符字符串来表示坐标。
猜你喜欢
  • 2011-10-23
  • 2011-06-21
  • 1970-01-01
  • 2021-12-17
  • 1970-01-01
  • 2012-08-31
  • 2011-08-16
  • 2019-09-13
相关资源
最近更新 更多