2010-09-21 2 views
7

ho bisogno di confrontare due oggetti ma confrontare un numero delle loro proprietà in un colpo. non è per l'ordinamento, ma per confermare se qualcosa è cambiato; come una è la vecchia istanza salvata, e la seconda è un'istanza appena importata della stessa cosacontrollando due istanze di oggetti per vedere se sono gli stessi

presumo che questo sia meglio servito scrivendo un comparatore personalizzato. sono solo un po 'confuso sul fatto di fare IComparer, o IComparable, o cosa tbh.

grazie

nat

+1

Questa è una buona domanda. Tutti i diversi confronti confondono anche me. – Greg

risposta

8

Se si dispone di un'unica definizione di uguaglianza per la classe, non è necessario implementare alcuna interfaccia: basta sovrascrivere il metodo Equals. Tuttavia, la migliore pratica sarebbe quella di implementare IEquatable<T> e di ridefinire sensibilmente GetHashCode (se non si sostituisce il codice hash, l'uguaglianza si comporta in modo anomalo quando le classi di raccolta, i metodi LINQ ecc. Lo usano come pre-condizione per l'uguaglianza). Ecco un esempio di implementazione:

public class Person : IEquatable<Person> 
{ 
    public string Name { get; set; } 
    public int Age { get; set; } 

    public override int GetHashCode() 
    { 
     return (Name == null ? 0 : Name.GetHashCode())^Age; 
    } 

    public override bool Equals(object obj) 
    { 
     return Equals(obj as Person); 
    } 

    public bool Equals(Person other) 
    { 
     return other != null && other.Name == Name && other.Age == Age; 
    } 
} 

Questo vi permetterà di fare:

Person savedPerson = ... 
Person importedPerson = ... 

bool hasChanged = !savedPerson.Equals(importedPerson); 

Se, d'altra parte, si ha un sacco di differenti definizioni di uguaglianza per circostanze diverse, la vostra la soluzione migliore sarebbe scrivere diverse implementazioni IEqualityComparer<T>. Ecco un esempio di implementazione:

public class AgeComparer : IEqualityComparer<Person> 
{ 
    public bool Equals(Person x, Person y) 
    { 
     return (x == null || y == null) ? x == y : x.Age == y.Age; 
    } 

    public int GetHashCode(Person obj) 
    { 
     return obj == null ? 0 : obj.Age; 
    } 
} 

In questo caso, il controllo sarà simile:

Person savedPerson = ... 
Person importedPerson = ... 
IEqualityComparer<Person> comparer = ... 

bool hasChanged = !comparer.Equals(savedPerson, importedPerson); 
+0

In che modo IEquatable è diverso da Equals definito su Object? – Greg

+0

sembra il suo IEqualityComparer per me in questo caso quindi, come ho bisogno di controllare un numero di proprietà del mio person.ie.managerID, phoneNumber, posizione ... ecc e se qualcuno di loro è cambiato ho bisogno del confronto per restituire falso .. a meno che mi manchi qualcosa? ma forse sono jsut incompreso cosa fa gethashcode .. – nat

+0

@nat: Sì, esattamente. – Ani

0

Sì è necessario il tipo di implementare IComparable. Here è un esempio su come farlo.

+7

Il tuo link punta a questo thread. Questo è un esempio di ricorsione, non IComparable;) – Marc

+1

lol @Marc. Grande cattura. –

+0

Forse intendeva collegare: http://support.microsoft.com/kb/320727 –

0

Come avete accennato IComparable è in genere utilizzato per l'ordinamento.

In questo caso si vorrebbe sovraccaricare l'operatore di confronto: ==

perché il confronto inverso dovrebbe anche essere valida, l'implica è necessario anche sovraccaricare l'operatore =!.

Quando si esegue il sovraccarico di == e!, È anche necessario eseguire l'override di Equals e GetHashCode.

Un buon libro in C# dovrebbe spiegare i dettagli.

0

Un'alternativa all'implementazione dell'interfaccia IComparable è quella di sostituire le funzioni Equals e GetHashCode.

0

Si tratta di come si desidera eseguire un'operazione di confronto. È possibile eseguire l'operazione in entrambi i modi:

public void Method() 
{ 
    Foo p1 = new Foo(); 
    Foo p2 = new Foo(); 

    p1.CompareTo(p2); 
    FooComparer c = new FooComparer(); 
    c.Compare(p1, p2); 
} 

class Foo : IComparable 
{ 
    public int CompareTo(object obj) 
    { 
     throw new NotImplementedException(); 
    } 
} 

class FooComparer : IComparer<Foo> 
{ 
    public int Compare(Foo x, Foo y) 
    { 
     throw new NotImplementedException(); 
    } 
} 

Preferisco utilizzare IComparer come separazione dei problemi. Foo è la mia classe, ho bisogno di qualche busines. Se voglio confrontare alcuni Foos, utilizzo FooComparer. Per la tua situazione puoi restituire il numero di proprietà modificate dal metodo Confronta. Se il metodo Compare restituisce 0. Quindi due Foos sono uguali.

Come ho detto. Questo è completamente il modo in cui vuoi eseguire l'azione che penso. Anche gli operatori di uguaglianza prevalenti sono una buona soluzione. L'implementazione di IEqualityComparer<T> è un'altra soluzione.