在Unity 3D中,我正在尝试构建一个由NodeCoordinates键控的PathNodes字典。我已经在NodeCoordinate中重写了GetHashCode,它应该返回一个常量唯一值。如果我循环遍历字典的键,查找工作正常,但如果我创建一个新的NodeCoordinate,其路径应该存在PathNode,即使哈希码相等,查找也会失败。
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class PathNode : MonoBehaviour {
public static Dictionary<NodeCoordinate, PathNode> pathNodes;
public PathNode left;
public PathNode right;
public PathNode forward;
public PathNode backward;
private NodeCoordinate coord;
void Awake()
{
if (PathNode.pathNodes == null)
{
PathNode.pathNodes = new Dictionary<NodeCoordinate, PathNode>();
}
NodeCoordinate coord = new NodeCoordinate(transform.position.x, transform.position.z);
this.coord = coord;
PathNode.pathNodes.Add(coord, this);
NodeCoordinate leftChord = new NodeCoordinate(coord.x - 1, coord.z);
NodeCoordinate rightChord = new NodeCoordinate(coord.x + 1, coord.z);
NodeCoordinate forwardChord = new NodeCoordinate(coord.x, coord.z + 1);
NodeCoordinate backwardChord = new NodeCoordinate(coord.x, coord.z - 1);
if (PathNode.pathNodes.ContainsKey(leftChord))
{
this.left = PathNode.pathNodes[leftChord];
this.left.right = this;
}
if (PathNode.pathNodes.ContainsKey(rightChord))
{
this.right = PathNode.pathNodes[rightChord];
this.right.left = this;
}
if (PathNode.pathNodes.ContainsKey(forwardChord))
{
this.forward = PathNode.pathNodes[forwardChord];
this.forward.backward = this;
}
if (PathNode.pathNodes.ContainsKey(backwardChord))
{
this.backward = PathNode.pathNodes[backwardChord];
this.backward.forward = this;
}
}
private static bool debug = true;
void Update()
{
if (debug)
{
foreach (NodeCoordinate coord in PathNode.pathNodes.Keys)
{
Debug.Log(coord + " : " + PathNode.pathNodes[coord] + " : " + coord.GetHashCode());
}
foreach (PathNode node in PathNode.pathNodes.Values)
{
NodeCoordinate leftChord = new NodeCoordinate(node.coord.x - 1, node.coord.z);
PathNode leftNode;
Debug.Log("Left: " + leftChord + " : " + PathNode.pathNodes.TryGetValue(leftChord, out leftNode) + " : " + leftChord.GetHashCode());
}
debug = false;
}
}
}
public class NodeCoordinate
{
public float x;
public float z;
public NodeCoordinate(float x, float z)
{
this.x = x;
this.z = z;
}
public bool Equals(NodeCoordinate coord)
{
return (this.x == coord.x && this.z == coord.z);
}
public override int GetHashCode()
{
return string.Format("{0}x{1}", this.x, this.z).GetHashCode();
}
public override string ToString()
{
return "Coordinate: " + this.x + " x " + this.z;
}
}
这是我的小调试的输出: debug log
正如您所看到的,在循环键时,使用哈希码2137067561和1824497336进行查找,但是当我实例化一个新的NodeCoordinate并尝试查找它时,它具有相同的哈希码,但查找失败。知道为什么会这样吗?感谢。
答案 0 :(得分:1)
问题是你的NodeCoordinate
类没有以字典使用的方式定义相等性。你有这样的方法:
public bool Equals(NodeCoordinate coord)
...但您既不会覆盖IEquatable<NodeCoordinate>
,也不会覆盖Equals(object)
。
我个人建议同时做这两件事 - 并实现一个不需要字符串格式化的简单哈希码:
public sealed class NodeCoordinate : IEquatable<NodeCoordinate>
{
public float X { get; }
public float Z { get; }
public NodeCoordinate(float x, float z)
{
X = x;
Z = z;
}
public override Equals(object other) => Equals(other as NodeCoordinate);
public bool Equals(NodeCoordinate coord) =>
coord != null && this.X == coord.X && this.Z == coord.Z;
public override int GetHashCode()
{
int hash = 23;
hash = hash * 31 + X;
hash = hash * 31 + Z;
return hash;
}
public override string ToString() => $"Coodinate: {X} x {Z}";
}
(请注意,我还使其不可变并使用属性而不是公共字段。为了简单起见,我使用了C#6语法,但如果转换为C#5则不难必要的。)
答案 1 :(得分:0)
因此,出于某种原因,当我添加具有完全相同逻辑的IEqualityComparer时,它可以工作。
将字典的声明更改为:
if (PathNode.pathNodes == null)
{
PathNode.pathNodes = new Dictionary<NodeCoordinate, PathNode>(new NodeCoordinateComparer());
}
补充说:
public class NodeCoordinateComparer : IEqualityComparer<NodeCoordinate>
{
public bool Equals(NodeCoordinate a, NodeCoordinate b)
{
return (a.x == b.x && a.z == b.z);
}
public int GetHashCode(NodeCoordinate coord)
{
return string.Format("{0}x{1}", coord.x, coord.z).GetHashCode();
}
}