Я интегрирую географический координатный класс из 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
должен иметь возможность обрабатывать его. -
Сравнение для равенства с использованием теста
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
(потому что это то, что сейчас) с соответствующими членами, можно увидеть здесь; комментарии и предложения более чем приветствуются.