Когда я должен использовать IEqualityComparer? C#
У меня есть список пользовательских объектов, где я пытаюсь удалить дубликаты записей. Я вижу так много онлайн статей, которые указывают на IEqualityComparer
(Я никогда не использовал это раньше).
Вопрос в том, когда мне его использовать? Я могу достичь того же результата путем LINQ
в одной строке кода.
Пример:
public static void Main(string[] args)
{
Product[] products =
{
new Product {Name = "apple", Code = 9},
new Product {Name = "orange", Code = 4},
new Product {Name = "apple", Code = 9},
new Product {Name = "lemon", Code = 12}
};
// Using Custom comparer
var usingCustomComparer = products.Distinct(new ProductComparer()).ToList();
// Using LINQ
var usinLinq = products.GroupBy(x => x.Name).Select(y => y.First()).ToList();
}
public class Product
{
public string Name { get; set; }
public int Code { get; set; }
}
// Custom comparer for the Product class
private class ProductComparer : IEqualityComparer<Product>
{
public bool Equals(Product x, Product y)
{
if (ReferenceEquals(x, y)) return true;
if (ReferenceEquals(x, null) || ReferenceEquals(y, null)) return false;
return x.Code == y.Code && x.Name == y.Name;
}
public int GetHashCode(Product product)
{
var hashProductName = product.Name == null ? 0 : product.Name.GetHashCode();
var hashProductCode = product.Code.GetHashCode();
return hashProductName ^ hashProductCode;
}
}
Результат от обоих:
{Name = "apple", Code = 9},
{Name = "orange", Code = 4},
{Name = "lemon", Code = 12}
3 ответа
когда я должен использовать это?
Некоторые возможности:
- Когда ваше определение "равенство" сложнее, чем просто сравнение одного свойства
- Когда вы хотите заранее определить "равенство" для использования во многих запросах
- Когда вы хотите определить "равенство" вне Linq, например, когда используете класс в качестве ключа к хеш-таблице
- Когда вы хотите немного изменить определение равенства, не повторяя код (т.е. включить / выключить чувствительность к регистру)
Следуя вашему примеру, скажем, что вы хотите сравнить объекты, игнорируя регистр, так что "Apple" и "яблоко" будут рассматриваться как один и тот же объект. Тогда ваш ProductComparer
может выглядеть так:
class ProductComparer : IEqualityComparer<Product>
{
public bool Equals(Product x, Product y)
{
if (ReferenceEquals(x, y)) return true;
if (ReferenceEquals(x, null) || ReferenceEquals(y, null)) return false;
return x.Code == y.Code && (x.Name.Equals(y.Name, StringComparison.InvariantCultureIgnoreCase));
}
public int GetHashCode(Product product)
{
var hashProductName = product.Name == null ? 0 : product.Name.ToLower().GetHashCode();
var hashProductCode = product.Code.GetHashCode();
return hashProductName ^ hashProductCode;
}
}
И это дало бы другие результаты, чем Linq.
В большинстве случаев сравнение может быть выполнено с некоторым количеством linq. Если оно одноразовое, выбор, скорее всего, зависит от личных предпочтений.
Если логика сравнения повторно используется изрядное количество, создавая IEqualityComparer
является стандартным и общеизвестным способом, принятым большинством API для сравнения двух объектов. Вы можете повторно использовать реализацию в методах linq, коллекциях и т. Д.