A HashSet<T>
делает удаляет дубликаты, потому что это набор ... но только тогда, когда ваш тип определяет равенство соответствующим образом.
Я подозреваю, по «продублировать» вы имеете в виду «объект с одинаковыми значениями поля к другому объекту» - вам необходимо изменить Equals
/GetHashCode
для этого на работу, и/или осуществлять IEquatable<Contact>
... или вы могли бы обеспечить IEqualityComparer<Contact>
к конструктору HashSet<T>
.
Вместо использования HashSet<T>
вы могли просто вызвать метод расширения Distinct
LINQ. Например:
list = list.Distinct().ToList();
Но опять-таки вам необходимо предоставить соответствующее определение равенства, так или иначе.
Вот пример реализации. Обратите внимание, как я сделал его неизменным (равенство нечетно с изменяемыми типами, потому что два объекта могут быть равны одной минуте и не равны следующей) и сделали поля private, с общедоступными свойствами. Наконец, я запечатал класс - неизменяемые типы, как правило, должны быть запечатаны, и это облегчает обсуждение равенства.
using System;
using System.Collections.Generic;
public sealed class Contact : IEquatable<Contact>
{
private readonly string firstName;
public string FirstName { get { return firstName; } }
private readonly string lastName;
public string LastName { get { return lastName; } }
private readonly string phoneNumber;
public string PhoneNumber { get { return phoneNumber; } }
public Contact(string firstName, string lastName, string phoneNumber)
{
this.firstName = firstName;
this.lastName = lastName;
this.phoneNumber = phoneNumber;
}
public override bool Equals(object other)
{
return Equals(other as Contact);
}
public bool Equals(Contact other)
{
if (object.ReferenceEquals(other, null))
{
return false;
}
if (object.ReferenceEquals(other, this))
{
return true;
}
return FirstName == other.FirstName &&
LastName == other.LastName &&
PhoneNumber == other.PhoneNumber;
}
public override int GetHashCode()
{
// Note: *not* StringComparer; EqualityComparer<T>
// copes with null; StringComparer doesn't.
var comparer = EqualityComparer<string>.Default;
// Unchecked to allow overflow, which is fine
unchecked
{
int hash = 17;
hash = hash * 31 + comparer.GetHashCode(FirstName);
hash = hash * 31 + comparer.GetHashCode(LastName);
hash = hash * 31 + comparer.GetHashCode(PhoneNumber);
return hash;
}
}
}
EDIT: Хорошо, в ответ на просьбы о объяснении GetHashCode()
реализации:
- Мы хотим объединить хэш-коду свойств этого объекта
- Мы не проверять для ничтожества в любом месте, поэтому мы должны предположить, что некоторые из них могут быть нулевыми.
EqualityComparer<T>.Default
всегда обрабатывает это, что приятно ... поэтому я использую это, чтобы получить хэш-код каждого поля.
- «Добавление и умножение» подхода к объединению нескольких хеш-кодов в один из них является стандартным, рекомендованным Джошем Блохом. Существует множество других алгоритмов хэширования общего назначения, но это отлично подходит для большинства приложений.
- Я не знаю, по умолчанию ли вы компилируете в проверенном контексте, поэтому я поставил вычисление в неконтролируемый контекст. We действительно все равно, если повторное умножение/добавление приводит к переполнению, потому что мы не ищем «величину» как таковую ... просто число, которое мы можем неоднократно использовать для равных объектов.
два альтернативных способа обработки недействительности, кстати:
public override int GetHashCode()
{
// Unchecked to allow overflow, which is fine
unchecked
{
int hash = 17;
hash = hash * 31 + (FirstName ?? "").GetHashCode();
hash = hash * 31 + (LastName ?? "").GetHashCode();
hash = hash * 31 + (PhoneNumber ?? "").GetHashCode();
return hash;
}
}
или
public override int GetHashCode()
{
// Unchecked to allow overflow, which is fine
unchecked
{
int hash = 17;
hash = hash * 31 + (FirstName == null ? 0 : FirstName.GetHashCode());
hash = hash * 31 + (LastName == null ? 0 : LastName.GetHashCode());
hash = hash * 31 + (PhoneNumber == null ? 0 : PhoneNumber.GetHashCode());
return hash;
}
}
Точно то, что я написал (если бы не было слишком поздно :-) –
Эта реализация GetHashCode() должна содержать пояснительные комментарии. Мой мозг не работает на вашем уровне. –
Можете ли вы, пожалуйста, метод GetHashCode, я, похоже, не следую этому примеру. – Sandy