Каждый раз, когда вы рассматриваете возможность использования IEqualityComparer<T>
, подумайте, можно ли сделать класс для реализации IEquatable<T>
. Если Product
всегда нужно сравнивать по идентификатору, просто определите его равным как таковому, чтобы вы могли использовать компаратор по умолчанию.
Тем не менее, есть еще несколько причин, по которым вам может понадобиться пользовательский компаратор:
- Если существует несколько способов, экземпляры класса можно считать равными. Лучший пример этого - строка, для которой платформа предоставляет шесть различных компараторов в
StringComparer
.
- Если класс определен таким образом, что вы не можете определить его как
IEquatable<T>
. Это будет включать классы, определенные другими, и классы, сгенерированные компилятором (в частности, анонимные типы, которые по умолчанию используют сравнение свойств).
Если вы решите, что вам нужен компаратор, вы, безусловно, можете использовать обобщенный компаратор (см. Ответ DMenT), но если вам нужно повторно использовать эту логику, вы должны инкапсулировать ее в выделенном классе. Вы даже можете объявить это, унаследовав от общей базы:
class ProductByIdComparer : GenericEqualityComparer<ShopByProduct>
{
public ProductByIdComparer()
: base((x, y) => x.ProductId == y.ProductId, z => z.ProductId)
{ }
}
Что касается использования, вы должны по возможности использовать преимущества компараторов. Например, вместо вызова ToLower()
для каждой строки, используемой в качестве ключа словаря (логика для которой будет разбросана по всему приложению), вы должны объявить словарь для использования без учета регистра StringComparer
. То же самое касается операторов LINQ, которые принимают компаратор. Но опять же, всегда учитывайте, является ли уравновешенное поведение, которое должно быть присуще классу, а не определено внешне.