A HashSet<T>
fa rimuovere i duplicati, perché è un set ... ma solo quando il tipo definisce l'uguaglianza in modo appropriato.
Ho il sospetto da "duplicato" si intende "un oggetto con valori di campo uguale ad un altro oggetto" - è necessario eseguire l'override Equals
/GetHashCode
per questo al lavoro, e/o implementare IEquatable<Contact>
... o si potrebbe fornire un IEqualityComparer<Contact>
al costruttore .
Invece di utilizzare un HashSet<T>
si potrebbe basta chiamare il metodo di estensione Distinct
LINQ. Ad esempio:
Ma ancora una volta, è necessario fornire una definizione appropriata di uguaglianza, in un modo o nell'altro.
Ecco un esempio di implementazione. Nota come l'ho reso immutabile (l'uguaglianza è dispari con i tipi mutabili, perché due oggetti possono essere uguali un minuto e non uguali al successivo) e resi i campi privati, con proprietà pubbliche. Infine, ho sigillato la classe - i tipi immutabili dovrebbero essere generalmente sigillati, e rende più facile parlare di uguaglianza.
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: Okay, in risposta alle richieste per una spiegazione del GetHashCode()
realizzazione:
- vogliamo unire i codici hash delle proprietà di questo oggetto
- Stiamo non controllare per nullità ovunque, quindi dovremmo assumere che alcuni di essi potrebbero essere nulli.
EqualityComparer<T>.Default
gestisce sempre questo, che è bello ... quindi lo sto usando per ottenere un codice hash di ogni campo.
- L'approccio "aggiungi e moltiplica" per combinare più codici hash in uno è quello standard consigliato da Josh Bloch. Esistono molti altri algoritmi di hashing generici, ma questo funziona bene per la maggior parte delle applicazioni.
- Non so se si sta compilando in un contesto controllato per impostazione predefinita, quindi ho messo il calcolo in un contesto non controllato. Noi davvero non importa se il ripetuto moltiplicare/aggiungere porta a un overflow, perché non stiamo cercando una "grandezza" in quanto tale ... solo un numero che possiamo raggiungere ripetutamente per oggetti uguali.
Due modi alternativi di gestire la nullità, tra l'altro:
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;
}
}
Esattamente quello che avevo scritto (se non fossi stato troppo tardi :-) –
Quella implementazione di GetHashCode() deve venire con commenti esplicativi. Il mio cervello non funziona al tuo livello. –
Potete per favore il metodo GetHashCode, non mi sembra di seguirlo. – Sandy