A HashSet<T>
elimina eliminar duplicados, porque es un conjunto ... pero solo cuando su tipo define la igualdad de forma apropiada.
sospecho por "duplicar" quiere decir "un objeto con valores de campo igual a otro objeto" - tiene que anular Equals
/GetHashCode
para que eso trabajo, y/o implementar IEquatable<Contact>
... o usted podría proporcionar una IEqualityComparer<Contact>
al constructor HashSet<T>
.
En lugar de utilizar un HashSet<T>
que podría simplemente llamar al método de extensión Distinct
LINQ. Por ejemplo:
list = list.Distinct().ToList();
Pero de nuevo, tendrá que proporcionar una definición adecuada de la igualdad, de alguna manera u otra.
Aquí hay una implementación de muestra. Observe cómo lo he hecho inmutable (la igualdad es impar con los tipos mutables, porque dos objetos pueden ser iguales un minuto y no igual al siguiente) y hicieron los campos privados, con propiedades públicas. Finalmente, he sellado la clase: los tipos inmutables generalmente deben sellarse, y hace que la igualdad sea más fácil de hablar.
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: Bueno, en respuesta a las peticiones de una explicación de la aplicación GetHashCode()
:
- queremos combinar los códigos hash de las propiedades de este objeto
- No estamos comprobando para la nulidad en cualquier lugar, por lo que debemos suponer que algunos de ellos pueden ser nulos.
EqualityComparer<T>.Default
siempre maneja esto, lo cual es bueno ... así que lo estoy usando para obtener un código hash de cada campo.
- El enfoque "agregar y multiplicar" para combinar varios códigos hash en uno es el estándar recomendado por Josh Bloch. Hay muchos otros algoritmos de hashing de propósito general, pero este funciona bien para la mayoría de las aplicaciones.
- No sé si está compilando en un contexto verificado de forma predeterminada, por lo que he puesto el cálculo en un contexto sin marcar. Nosotros realmente no importa si la multiplicación/agregación repetida conduce a un desbordamiento, porque no estamos buscando una "magnitud" como tal ... solo un número que podemos alcanzar repetidamente para objetos iguales.
Dos formas alternativas de manejo de nulidad, por cierto:
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;
}
}
o
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;
}
}
Exactamente lo que escribí (si no hubiera sido demasiado tarde :-) –
Esa implementación de GetHashCode() debe venir con comentarios explicativos. Mi cerebro no funciona en tu nivel. –
¿Puede agradar al método GetHashCode, no parece seguir eso. – Sandy