IComparable.Compare для правильной реализации с учетом наследования - PullRequest
0 голосов
/ 03 сентября 2018

Вопрос связан с структурой сущности и в сортировке памяти.

Чтение этой статьи
https://docs.microsoft.com/en-us/dotnet/api/system.icomparable.compareto?view=netframework-4.7.2
Я должен выбросить исключение, если классы не относятся к одному и тому же типу (или, глядя на пример, сравниваемый класс не является экземпляром сопоставимого класса).
Я использую GetType().IsInstanceOfType(obj)), чтобы определить, должен ли я выдать InvalidArgumentException, как того требует спецификация API.

У меня 2 класса

public class MyClass : IComparable
{
    // ...
}

public class MyClassProxy : MyClass
{
    // This class rappresent an EF proxy
    // ...
}

При применении спецификации API MyClass.CompareTo(MyClassProxy) должно работать нормально, в то время как MyClassProxy.CompareTo(MyClass) не должно работать.

Вопрос в том, должен ли я в этом случае точно соблюдать определение API или частично снять ограничение API для типов и не выбрасывать исключение, если класс является прокси сопоставимого класса?

Если я сниму ограничение, как правильно проверить совместимость типов?

1 Ответ

0 голосов
/ 03 сентября 2018

Интересно, будет ли у вас такой же вопрос, если бы MyClass реализовал IComparable<MyClass> вместо или (или, может быть, так же, как) IComparable

Давайте сделаем тот же вопрос с менее абстрактным примером.

Предположим, у нас есть класс Animal. Каждое животное имеет NumberOfLegs. Мы хотели бы заказать животных на это количество ног, поэтому мы реализуем IComparable<Animal>.

Предположим, у нас также есть класс Human, производный от Animal (хотя некоторые будут сомневаться в этом). Каждый Human имеет Name, и мы хотели бы заказать Humans по имени, поэтому мы реализуем IComparable<Human>

Точно так же у нас есть Spider, который, конечно, является восьминогим Animal:

class Animal : IComparable<Animal> {...}
class Spider : Animal, IComparable<Spider> {...}
class Human : Animal, IComparable<Human> {...}

Легко ответить будет следующее: каковы значения x и y?

Animal spider = new Spider();
Animal bill = new Human("William Shakespeare");
int x = spider.CompareTo(bill);  // +1 A spider has more legs than bill
int y = bill.CompareTo(spider);  // -1: bill has less legs than Spider

Давайте сделаем это снова: каково значение z?

Spider spider = new Spider();
Human bill = new Human("William Shakespeare");
int z = bill.CompareTo(spider); // ???

Каким вам хотелось бы быть значение этого ? Класс Human не реализует IComparable<Spider>, и не все Пауки имеют имя. Таким образом, все, что мы можем сделать, это сравнить по количеству ног, что и произойдет.

Если вам действительно нужна особая обработка при сравнении людей и пауков (например, с помощью фактора страха), вы должны позволить человеку реализовать IComparable<Spider> (или наоборот).

Теперь, когда вы точно знаете, что будете делать, когда будете внедрять IComparable<Human>, IComparable<Animal> и т. Д. Я думаю, вы будете знать, что делать, если вы также внедрите IComparable

Последнее замечание : Реализуйте IComparable<...> только для класса, если ваш метод сравнения типичен для объектов класса. Это если все скажут, что ваш метод - это естественный способ упорядочения объектов такого типа.

Это не естественный способ заказывать животных по количеству ног. Поэтому читатели не будут инстинктивно знать, что сделают следующее:

IEnumerable<Animal> myAnimals = ...
var result = myAnimals.OrderBy(animal => animal);

Animal не должен был реализовывать IComparable подобным образом. Мы должны создать специальный класс Comparer, который реализует IComparer<Animal> для количества ветвей:

class AnimalLegCountCompare: IComparer<Animal> {...}

Следующее будет менее запутанным для читателей:

ICompared<Animal> legCountComparer = new AnimalLegCountComparer();
var result = myAnimals
   .OrderBy(animal=>animal, legCountComparer);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...