[英]IEqualityComparer and weird results
Take a look at this class: 看一看这个课程:
public class MemorialPoint:IMemorialPoint,IEqualityComparer<MemorialPoint>
{
private string _PointName;
private IPoint _PointLocation;
private MemorialPointType _PointType;
private DateTime _PointStartTime;
private DateTime _PointFinishTime;
private string _NeighborName;
private double _Rms;
private double _PointPdop;
private double _PointHdop;
private double _PointVdop;
// getters and setters omitted
public bool Equals(MemorialPoint x, MemorialPoint y)
{
if (x.PointName == y.PointName)
return true;
else if (x.PointName == y.PointName && x.PointLocation.X == y.PointLocation.X && x.PointLocation.Y == y.PointLocation.Y)
return true;
else
return false;
}
public int GetHashCode(MemorialPoint obj)
{
return (obj.PointLocation.X.ToString() + obj.PointLocation.Y.ToString() + obj.PointName).GetHashCode();
}
}
I also have a Vector class, which is merely two points and some other atributes. 我也有一个Vector类,它只有两点和其他一些属性。 I don't want to have equal points in my Vector, so I came up with this method:
我不想在Vector中拥有相等的点,所以我想出了以下方法:
public void RecalculateVector(IMemorialPoint fromPoint, IMemorialPoint toPoint, int partIndex)
{
if (fromPoint.Equals(toPoint))
throw new ArgumentException(Messages.VectorWithEqualPoints);
this.FromPoint = FromPoint;
this.ToPoint = ToPoint;
this.PartIndex = partIndex;
// the constructDifference method has a weird way of working:
// difference of Point1 and Point 2, so point2 > point1 is the direction
IVector3D vector = new Vector3DClass();
vector.ConstructDifference(toPoint.PointLocation, fromPoint.PointLocation);
this.Azimuth = MathUtilities.RadiansToDegrees(vector.Azimuth);
IPointCollection pointCollection = new PolylineClass();
pointCollection.AddPoint(fromPoint.PointLocation, ref _missing, ref _missing);
pointCollection.AddPoint(toPoint.PointLocation, ref _missing, ref _missing);
this._ResultingPolyline = pointCollection as IPolyline;
}
And this unit test, which should give me an exception: 而这个单元测试,应该给我一个例外:
[TestMethod]
[ExpectedException(typeof(ArgumentException), Messages.VectorWithEqualPoints)]
public void TestMemoriaVector_EqualPoints()
{
IPoint p1 = PointPolygonBuilder.BuildPoint(0, 0);
IPoint p2 = PointPolygonBuilder.BuildPoint(0, 0);
IMemorialPoint mPoint1 = new MemorialPoint("teste1", p1);
IMemorialPoint mPoint2 = new MemorialPoint("teste1", p2);
Console.WriteLine(mPoint1.GetHashCode().ToString());
Console.WriteLine(mPoint2.GetHashCode().ToString());
vector = new MemorialVector(mPoint1, mPoint1, 0);
}
When i use the same point, that is, mPoint1, as in the code the exception is thrown. 当我使用同一点(即mPoint1)时,如代码中所示,将引发异常。 When I use mPoint2, even their name and coordinates being the same, the exception is not thrown.
当我使用mPoint2时,即使它们的名称和坐标相同,也不会引发异常。 I checked their hash codes, and they are in fact different.
我检查了他们的哈希码,实际上它们是不同的。 Based on the code I created in GetHashCode, I tought these two point would have the same hashcode.
基于我在GetHashCode中创建的代码,我坚称这两点将具有相同的哈希码。
Can someone explain to me why this is not working as I tought it would? 有人可以向我解释为什么这不起作用吗? I'm not sure I explained this well, but.. I appreciate the help :D
我不确定我解释得很好,但是..我感谢您的帮助:D
George 乔治
You're implementing IEqualityComparer<T>
within the type it's trying to compare - which is very odd. 您正在尝试比较的类型内实现
IEqualityComparer<T>
-这很奇怪。 You should almost certainly just be implementing IEquatable<T>
and overriding Equals(object)
instead. 几乎可以肯定,您应该只是实现
IEquatable<T>
并改写Equals(object)
。 That would definitely make your unit test work. 那肯定会使您的单元测试工作。
The difference between IEquatable<T>
and IEqualityComparer<T>
is that the former is implemented by a class to say, "I can compare myself with another instance of the same type." IEquatable<T>
和IEqualityComparer<T>
之间的区别在于,前者是由一个类实现的,它表示“我可以将自己与另一个相同类型的实例进行比较”。 (It doesn't have to be the same type, but it usually is.) This is appropriate if there's a natural comparison - for example, the comparison chosen by string
is ordinal equality - it's got to be exactly the same sequence of char
values. (它不必是同一类型,但它通常是。)这是合适的,如果有一个自然的比较-例如,通过选择比较
string
是有序的平等-这一定是完全相同的同一序列char
值。
Now IEqualityComparer<T>
is different - it can compare any two instances of a type. 现在
IEqualityComparer<T>
有所不同-它可以比较类型的任何两个实例。 There can be multiple different implementations of this for a given type, so it doesn't matter whether or not a particular comparison is "the natural one" - it's just got to be the right one for your job. 对于给定的类型,可以有多种不同的实现方式,因此,特定的比较是否为“自然比较”并不重要-只是适合您的工作。 So for example, you could have a
Shape
class, and different equality comparers to compare shapes by colour, area or something like that. 因此,例如,您可以拥有一个
Shape
类,并使用不同的相等比较器来按颜色,面积或类似方式比较形状。
You need to override Object.Equals
as well. 您还需要重写
Object.Equals
。
Add this to your implementation: 将此添加到您的实现中:
// In MemorialPoint:
public override bool Equals(object obj)
{
if (obj == null || GetType() != obj.GetType())
return false;
MemorialPoint y = obj as MemorialPoint;
if (this.PointName == y.PointName)
return true;
else if (this.PointName == y.PointName && this.PointLocation.X == y.PointLocation.X && this.PointLocation.Y == y.PointLocation.Y)
return true;
else
return false;
}
I'd then rework your other implementation to use the first, plus add the appropriate null checks. 然后,我会重做您的其他实现以使用第一个实现,并添加适当的null检查。
public bool Equals(MemorialPoint x, MemorialPoint y)
{
if (x == null)
return (y == null);
return x.Equals(y);
}
You also need to rethink your concept of "equality", since it's not currently meeting .NET framework requirements . 您还需要重新考虑“平等”的概念,因为它目前不满足.NET Framework 要求 。
If at all possible, I recommend a re-design with a Repository of memorial point objects (possibly keyed by name), so that simple reference equality can be used. 如果可能的话,我建议重新设计一个带有纪念点对象的存储库(可能用名称作为关键字),以便可以使用简单的引用相等性。
You've put an arcobjects tag on this, so I just thought I'd mention IRelationalOperator.Equals . 您已经在此对象上放置了一个arcobjects标记,所以我以为我要提到IRelationalOperator.Equals 。 I've never tested to see if this method honors the cluster tolerance of the geometries' spatial references.
我从未测试过这种方法是否符合几何空间参考的簇公差。 This can be adjusted using ISpatialReferenceTolerance.XYTolerance .
可以使用ISpatialReferenceTolerance.XYTolerance进行调整。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.