我正在将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;
}
在这一点上,我停下来,并认为我正在比较浮点变量的相等性,这通常是禁忌。我的思考过程大致如下:
我只能想象设置
Latitude和Longitude属性一次,这意味着不会累积任何错误来搞砸我的比较。另一方面,写(尽管没有意义)是可能的
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应该能够处理它。使用a比较相等性
difference < epsilontest会解决比较两个实例的问题,但会产生更多问题:- 如何使平等传递?听起来不可能。
如何生产 相同 哈希代码 所有 比较相等的价值?
我们这样说吧
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 (因为这就是现在的情况)可以看到相关成员 这里;评论和建议超过欢迎。