我正在将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 < epsilon
test会解决比较两个实例的问题,但会产生更多问题:- 如何使平等传递?听起来不可能。
如何生产 相同 哈希代码 所有 比较相等的价值?
我们这样说吧
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
(因为这就是现在的情况)可以看到相关成员 这里;评论和建议超过欢迎。