Реализация IComparable<NotSelf>
Это может быть тривиальный вопрос, но я не нашел никакой информации по этому поводу: "вредно" или считается плохой практикой, чтобы внедрить тип T IComparable<S>
(T и S два разных типа)?
Пример:
class Foo : IComparable<int>
{
public int CompareTo(int other)
{
if (other < i) return -1;
if (other > i) return 1;
return 0;
}
private int i;
}
Следует ли избегать такого рода кода, и если да, то почему?
3 ответа
Я бы, по крайней мере, счел это "странным" - в частности, в этот момент сравнение не будет симметричным, что обычно является частью обычных договоров сравнения.
Если есть конкретная ситуация, когда это проще, чем любая другая реализация того, что вы хотите сделать, это было бы хорошо - но я не могу сказать, что когда-либо сталкивался с такой ситуацией. Подобные сравнения почти всегда используются для сортировки однородной коллекции или чего-то подобного.
Вы имели в виду конкретную ситуацию или это просто вопрос "для интереса"?
Это необычно для реализации таких вещей. Но это не очень хорошая практика.
Представьте, что вы видите такой код:
Foo x = new Foo();
if( x.compareTo(15) > 0)
{
//blah blah
}
Вы скажете: "Боже мой! Как сравнить 15 с х?"? Это сделает код менее читабельным.
Лучше добавить сравнение как функцию: public int IsMoreThanPrivateI(int x);
Я вижу применение для сравнения объектов разных классов, но я не думаю, что IComparable(из T) является правильной основой. Чтобы такие сравнения действительно работали, объекты должны иметь общую каноническую форму, которая подразумевает, что все они были получены от общего предка или реализуют общий интерфейс. Я также хотел бы предложить, чтобы эта общая база включала метод SecondChanceCompareTo, и обычный метод сравнения должен, если он не распознает точный тип, с которым он сравнивается, передавать себя в метод SecondChanceCompare переданного объекта.
В качестве примера того, где этот тип вещей может быть полезен, представьте семейство классов, которые хранят строки; строка может быть сохранена как простой объект String, но некоторые строки могут быть сохранены как символ и счетчик повторений, другие могут быть сохранены как ссылка на более длинную строку наряду с начальным смещением и длиной, и т. д. Сравните два строковых объекта, преобразовав их в тип "String", а затем выполнив сравнение, но существует много сценариев, в которых существуют лучшие средства сравнения. Например, если одна строка сохраняется как "Символ" Z ", повторенный 100000 раз", а другая строка сохраняется как "Литеральная строка" Собака "", первая строка может сравнивать себя с последней, наблюдая, что первый символ последнего был меньше, чем "Z".
Обратите внимание, что базовый объект "буквальная строка" может не знать, как сравнивать себя со строковым объектом "повторяющийся символ", за исключением преобразования последнего в буквенную строку (дорогая операция), но он может вызывать метод "SecondChanceCompare" последнего, который бы знал, как сравнить себя с литеральной строкой.