我正在将一个地理坐标类从codeplex集成到我的个人“工具箱”库中。这个类使用float字段来存储纬度和经度。
由于类GeoCoordinate实现IEquatable<GeoCoordinate>,我习惯性地编写Equals方法,如下所示:

public bool Equals(GeoCoordinate other)
{
    if (other == null) {
        return false;
    }

    return this.latitude == other.latitude && this.longitude == other.longitude;
}

在这一点上,我停下来思考,我正在比较浮点变量是否相等,这通常是一个否定的问题,然后我的思考过程大致如下:
我只能想象一次设置LatitudeLongitude属性,这意味着不会累积错误来搞乱我的比较。
另一方面,写作是可能的(尽管毫无意义)
var geo1 = new GeoCoordinate(1.2, 1.2);
var geo2 = new GeoCoordinate(1.2, 1.2);

// geo1.Equals(geo2) will definitely be true, BUT:

geo2.Latitude *= 10;
geo2.Latitude /= 10;

// I would think that now all bets are off

当然,这不是我能想象的,但是如果类的公共接口允许它,那么Equals应该能够处理它。
使用difference < epsilon测试比较相等性可以解决比较两个实例的问题,但会产生更多的问题:
如何使平等具有及物性?听起来不可能。
如何为比较相等的所有值生成相同的哈希代码?
假设epsilon = 0.11(随机示例)。因此GeoCoordinate { 1, 1 }需要与GeoCoordinate { 1.1, 1.1 }相同的散列代码。但后者需要与GeoCoordinate { 1.2, 1.2 }相同的散列代码。您可以看到这将发生什么:所有实例都需要具有相同的哈希代码。
所有这些问题的解决方案是使GeoCoordinate成为一个不可变的类。这也可以解决GetHashCode问题:它基于纬度和经度(还有什么),如果这些是可变的,那么使用GeoCoordinate作为字典中的键就麻烦了。但是,使类不可变有其自身的缺点:
不能实例化和配置类的实例(wpf范型),这在某些情况下可能是一种痛苦。
序列化也可能会因为失去一个无参数的构造函数而成为一种痛苦(我不是.NET序列化专家,所以这和我在这里看到的一样详细)
你建议采用哪种方法?很容易使类满足我现在的需求(只需使其不可变),但是有更好的方法吗?
编辑:我在上面的列表中添加了一个项目3,将前面的项目3移到位置4。
解决方案
我会给你更多的反馈时间,但现在我要用不变的方法。struct(因为现在就是这样),相关成员可以看到here;意见和建议更受欢迎。

最佳答案

对我来说,经度/纬度的“位置”很好地落入了“不可变值”的槽中。位置本身不会改变-如果你改变纬度,那是一个不同的位置。从那里,它可能是一个struct;对于floatstruct无论如何都将与x64引用的大小相同,因此没有真正的下边。
是平等的;如果位置不完全相同,它就不是“平等的”,至少从“关键”的角度来看,所以我很高兴这里有==。如果有帮助,您可以添加一个“is within(x)distance”方法。当然,伟大的弧线几何也不是完全自由的;p
尽管如此:
它应该覆盖bool Equals(object)并添加一个bool Equals(GeoCoordinate)
它应该覆盖GetHashCode()并实现IEquatable<GeoCoordinate>
静态运算符是一个很好的选择额外的

07-27 20:33