Уникальность словаря C # для родственных классов с использованием IEquatable <T> - PullRequest
2 голосов
/ 23 апреля 2010

Я хотел бы хранить элементы двух классов в структуре словаря и использовать IEquatable для определения уникальности этих экземпляров. Оба этих класса имеют (абстрактный) базовый класс. Рассмотрим следующие классы:

abstract class Foo
{
   ...
}

class SubFoo1 : Foo
{
   ...
}

class SubFoo2 : Foo
{
   ...
}

Словарь будет удален: Dictionary<Foo, Bar>

Какие классы должны быть объявлены как IEquatable? И каким должен быть общий тип T для этих объявлений? Это вообще возможно?

Ответы [ 5 ]

4 голосов
/ 23 апреля 2010

Не объявляйте ничего как IEquatable<T>. Как правило, это проблема, когда речь идет о наследовании и равенстве, как говорит Марк.

Вместо этого выясните, какое равенство вы хотите получить для ключей в этом конкретном словаре, и реализуйте IEqualityComparer<Foo>, затем передайте это в конструктор словаря.

Обычно достаточно понятно, как сравнивать ключи для конкретной ситуации.

0 голосов
/ 13 июня 2012

Наследуемые классы почти никогда не должны реализовывать IEquatable<T>. Для любого типа T каждый объект, который реализует IEquatable<T>, должен делать так, чтобы семантика IEquatable<T>.Equals соответствовала семантике Object.Equals. Если класс реализует IEquatable<Foo> для некоторого Foo, а производный класс изменяет семантику Object.Equals, но не реализует повторно IEquatable<Foo>.Equals, единственный способ семантики последнего будет соответствовать первому, если интерфейс реализация просто вызывает виртуальный Object.Equals сам; если интерфейс просто передает свой аргумент Object.Equals, его реализация бесполезна.

0 голосов
/ 23 апреля 2010

Вы всегда можете указать свой собственный компаратор равенства в конструкторе словаря. Если вы этого не сделаете, словарь будет искать IEquatable<TKey>, так что в вашем случае для IEquatable<Foo>, поэтому вы должны реализовать это.

0 голосов
/ 23 апреля 2010

Когда вы начинаете получать наследство, действительно сложно выбрать T. Базовый тип является очевидным выбором, но мне интересно, не лучше ли просто переопределить Equals и GetHashCode.

Вы также можете заключить, что такие сложные сценарии могут быть плохим выбором для ключа, и вместо этого использовать более простой, более предсказуемый ключ. В частности, вы хотите, чтобы «хэш» основывался на некотором неизменном фасете типа, а «хэш» и «равно» должны быть совместимы. Эти нюансы очень сложно гарантировать, если тип не sealed.

0 голосов
/ 23 апреля 2010

Это зависит от того, за что вы выступаете.Так что нет никакого «общего» решения для этого.Если бы было, то System.Object реализовал бы IEquatable<object>, так как все уже наследуется от object в любом случае.Таким образом, вы могли бы задать тот же вопрос о Object вместо Foo.

Короче говоря, это зависит от того, чего вы хотите достичь с помощью вашей иерархии классов.

Короче говоряЯ согласен, что в любом случае сложно определить, что делает объекты равными, потому что даже для одного и того же типа объекта могут быть разные требования.Когда вы используете кэш, равенство будет определяться идентификатором объекта.Когда вы используете Do- / Undo-List, вам понадобится другой классификатор, потому что идентификатор, вероятно, будет одинаковым для каждого объекта в списке.

Думаю, я немного отступил, но надеюсь, что смогу датьВы некоторые полезные моменты.; -)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...