2010-07-07 2 views
37

Durante l'apprendimento .net (di C#) ho trovato 5 modi per controllare l'uguaglianza tra gli oggetti.5 modi per il controllo dell'uguaglianza in .net .. perché? e quale usare?

  1. Il metodo ReferenceEquals().
  2. Il metodo virtuale Equals(). (System.Object)
  3. Il metodo statico Equals().
  4. Il metodo Equals dall'interfaccia IEquatable.
  5. L'operatore di confronto ==.

La mia domanda è:

  1. perché ci sono così tanti metodo Equals() insieme con l'operatore di confronto?
  2. Quale tra le Equals virtuali() o il metodo() sholud essere utilizzato .. (per esempio se usiamo le nostre classi di insiemi)

risposta

26

1 - riferimento uguale controlla se le variabili di tipo due riferimento (classi, non struct) sono riferiti allo stesso indirizzo di memoria.

2 - The Equals virtuali() controlla metodo se due oggetti sono equivalenti.Diciamo che avete questa classe:

class TestClass{ 
    public int Property1{get;set} 
    public int Property2{get;set} 

    public override bool Equals(object obj) 
    { 
     if (obj.GetType() != typeof(TestClass)) 
      return false; 

     var convertedObj = (TestClass)obj; 

     return (convertedObj.Property1 == this.Property1 && convertedObj.Property2 == this.Property2); 
    } 
} 

e si crea un'istanza di 2 oggetti da quella classe:

var o1 = new TestClass{property1 = 1, property2 = 2} 
var o2 = new TestClass{property1 = 1, property2 = 2} 

anche se i due oggetti non sono la stessa istanza di TestClass, la chiamata a o1.Equals (o2) restituirà true.

3 - Il metodo statico Equals viene utilizzato per gestire i problemi quando nel controllo è presente un valore nullo. Immaginate questo, per esempio:

TestClass o1 = null; 
var o2 = new TestClass{property1 = 1, property2 = 2} 

Se si tenta questo:

o1.Equals(o2); 

si wil ottenere un NullReferenceException, perché i punti da O1 a nulla. Per risolvere il problema, procedere come segue:

Object.Equals (o1, o2);

Questo metodo è preparato per gestire riferimenti null.

4 - L'interfaccia IEquatable è fornita da .Net quindi non è necessario eseguire cast nel metodo Equals. Se il compilatore scopre di aver implementato l'interfaccia in una classe per il tipo che si sta tentando di controllare per l'uguaglianza, darà la priorità di quel metodo sull'override Object.Equals (Object). Per esempio:

class TestClass : IEquatable<TestClass> 
{ 
    public int Property1 { get; set; } 
    public int Property2 { get; set; } 

    public override bool Equals(object obj) 
    { 
     if (obj.GetType() != typeof(TestClass)) 
      return false; 

     var convertedObj = (TestClass)obj; 

     return (convertedObj.Property1 == this.Property1 && convertedObj.Property2 == this.Property2); 
    } 

    #region IEquatable<TestClass> Members 

    public bool Equals(TestClass other) 
    { 
     return (other.Property1 == this.Property1 && other.Property2 == this.Property2); 
    } 

    #endregion 
} 

ora se facciamo questo:

var o1 = new TestClass{property1 = 1, property2 = 2} 
var o2 = new TestClass{property1 = 1, property2 = 2} 
o1.Equals(o2); 

Il metodo chiamato è Equals (testclass), prima Equals (Object).

5 - L'operatore == di solito corrisponde a ReferenceEquals, controlla se due variabili puntano allo stesso indirizzo di memoria. Il trucco è che questo operatore può essere ignorato per eseguire altri tipi di controlli. Nelle stringhe, ad esempio, controlla se due diverse istanze sono equivalenti.

Questo è un link utile per capire uguaglianze in .Net meglio:

+0

Eccellente. Gli esempi aiutano veramente, ma c'è un errore di battitura nel tuo punto 4, dove IEquatable.Equals usa ancora 'convertedObj' – PaulG

+0

Grazie PaulG, ora è riparato! =] – mverardo

29

I ReferenceEquals() Equals di IEquatable.

Questo è utilizzato per verificare se due variabili date puntano (i riferimenti ai simboli) allo stesso oggetto. È letteralmente equivalente a ((object)a) == ((object)b). Se si sostituisce l'operatore di confronto (==), allora ReferenceEquals mantiene un modo per accedere al comportamento predefinito.

Tuttavia, se si ha a che fare con un tipo di valore (ad esempio una struct), quindi questo will always return false. Questo perché il confronto inserisce ogni tipo di valore in un nuovo oggetto, quindi naturalmente i riferimenti non saranno uguali. Metodo


The Equals virtuali(). (System.Object)

Questo è il modo predefinito per confrontare semanticamente due oggetti (di qualsiasi tipo). Ogni classe ha la priorità su ciò che preferisce. Per impostazione predefinita è equivalente a una chiamata CLR (InternalEquals) che sostanzialmente confronta i riferimenti di memoria.

Nota, se due oggetti restituiscono true per Equals() quindi GetHashCode() su ognuno di essi must be equal. Tuttavia, se i codici hash per due oggetti sono equivalenti al valore (ad esempio obj1.GetHashCode() == obj2.GetHashCode()), questo non significa che Equals() è vero.

La classe deve in genere implementare Equals e GetHashCode come mezzo per distinguere le istanze di classe e deve implementare questo o l'operatore == (idealmente entrambi) se si tratta di un tipo di valore.

nota, per i tipi di valore del Equals comportamento predefinito è quello di ValueType.Equals() che se si guarda in Reflector (o leggere the MSDN description) utilizza la reflection per confrontare i membri delle due istanze di valore.Metodo


The Equals statici().

Ciò equivale a return ((objA == objB) || (((objA != null) && (objB != null)) && objA.Equals(objB))) dove ogni tipo viene convertito Object per il test. Il mio test mostra che gli operatori di confronto sovraccarico vengono ignorati, ma il tuo metodo Equals verrà utilizzato se gli oggetti non sono nulli e non sono lo stesso riferimento. Pertanto, a.Equals(b) non equivale necessariamente a object.Equals(a, b) (per i casi in cui ((object)a) == ((object)b) o aob è nullo).


Il metodo Equals dall'interfaccia IEquatable.

IEquatable offre un modo per trattare in modo specifico il confronto con istanze della stessa classe. Dopo aver detto che il vostro metodo di Equalsshould be handling the behaviour the same way:

Se si implementa Equals, si dovrebbe ignorare anche la classe di base implementazioni di Object.Equals (oggetto) e GetHashCode modo che il loro comportamento è coerente con quella di le IEquatable.Equals metodo

Nevertheless you should implement IEquatable:

Per gestire la possibilità che gli oggetti di una classe verranno memorizzati in una matrice o un oggetto di insieme generico, è una buona idea per attuare IEquatable modo che l'oggetto possa essere facilmente individuato e manipolato.


Il confronto operatore ==

L'operatore di confronto da ritorni di default vero quando entrambi i vostri oggetti sono lo stesso riferimento.

Si is not recommended Per sostituire l'operatore di confronto meno si tratta with a value type (nel qual caso è consigliabile, insieme al metodo Equals) o un tipo di riferimento immutabile che di solito si confronta per valore (ad esempio string). Attuare sempre != allo stesso tempo (in effetti ottengo un errore requires a matching operator '!=' to also be defined se non lo faccio).


Risorse:

+2

Ottima risposta. +1 – RPM1984

0

Per primitive, bastone con l'operatore ==.

Nella maggior parte degli oggetti forniti nel framework .NET e in tutti gli oggetti personalizzati viene creato il metodo .Equals() e l'operatore == controlla solo se due oggetti si riferiscono allo stesso oggetto nell'heap.

Lo scopo dell'interfaccia IEquatable è quello di sostituire il metodo .equals() per cambiare il suo comportamento da controllare per l'uguaglianza di riferimento per verificare l'uguaglianza valore. Il tipo System.String è un esempio di un oggetto .NET incorporato che implementa questa interfaccia.

Il metodo .ReferenceEquals() offre agli sviluppatori che hanno superato il metodo standard .Equals() di essere ancora in grado di controllare due oggetti per l'uguaglianza referenziale.

+2

"Primitivi"? Questo non è Java, mang! – Randolpho

1

Ogni versione di uguaglianza è leggermente diversa.

ReferenceEquals test per l'uguaglianza riferimento.

virtual Equals da controlli di default per l'uguaglianza di riferimento per i tipi di classe e l'uguaglianza il valore per i tipi di struct. Può essere sovrascritto definire l'uguaglianza in modo diverso, se lo si desidera; e dovrebbe essere sovrascritto per i tipi di valore.

static Equals chiama solo virtual Equals, ma consente anche argomenti null.

IEquatable<T>.Equals è un equivalente generico/sicuro per virtual Equals.

operator== è destinato ad essere come il default virtual Equals, il che significa l'uguaglianza di riferimento per i tipi di classe (a meno che la classe ha la precedenza anche altri operatori). Dovrebbe anche essere sovrascritto per i tipi di valore.

Se si scrive la propria classe di raccolta, utilizzare IEqualityComparer<T>, per impostazione predefinita su EqualityComparer<T>.Default. Non utilizzare nessuno dei confronti di uguaglianza direttamente.

+0

thnx .. per la risoluzione dei dubbi sull'implementazione della nostra classe di raccolta – Gaurav