2009-09-27 10 views
14

Sto riscontrando un comportamento diverso tra l'utilizzo di .Equals e == tra due delle nuove istanze di .NET 4.0 di Tuple <>. Se ho effettuato l'override uguale all'oggetto nella tupla <> e chiamo .Equals sulle tuple, verrà chiamato l'override di Equals. Se uso == sulle tuple, l'override di Equals non viene chiamato. È di progettazione e ha senso?Si prevede questo comportamento di uguaglianza Tuple C# 4.0?

MODIFICA: Da risposte e commenti posso dire che non sono stato chiaro. So che Tuple <> è un tipo di riferimento e che per i tipi di riferimento == controllerà l'identità (ReferenceEquals). Ma, dovrebbe Tuple <> override == per controllare l'uguaglianza degli oggetti che contiene? Per coerenza, probabilmente no.

Per esempio se ho un semplice oggetto

public class NameAndNumber 
{ 
    public int Number { get; set; } 
    public string Name { get; set; } 

    public override bool Equals(object obj) 
    { 
     if (obj is NameAndNumber) 
     { 
      NameAndNumber other = (NameAndNumber)obj; 
      return Number == other.Number && Name == other.Name; 
     } 

     return false; 
    } 
} 

e poi faccio qualcosa di simile:

Tuple<NameAndNumber, NameAndNumber> left = new Tuple<NameAndNumber, NameAndNumber>(
     new NameAndNumber { Name = "one", Number = 1 }, 
     new NameAndNumber { Name = "two", Number = 2 }); 
Tuple<NameAndNumber, NameAndNumber> right = new Tuple<NameAndNumber, NameAndNumber>(
     new NameAndNumber { Name = "one", Number = 1 }, 
     new NameAndNumber { Name = "two", Number = 2 }); 
bool operatorResult = left == right; 
bool equalsResult = left.Equals(right); 
Console.Out.WriteLine("operatorResult = {0} equalsResult = {1}", 
     operatorResult, equalsResult); 

ottengo operatorResult = false equalsResult = true

Dovrei essere in attesa quella?

So che l'implementazione di Equals su NameAndNumber non è "corretta" ma solo codice di esempio semplificato.

Ho anche provato a implementare IEquatable, ==,! = E GetHashCode. Stessi risultati

+0

Grazie per le risposte e i commenti. Avrei dovuto aspettarmi questo comportamento. Sto sostituendo i nostri progetti 3.5 Implementazione di tuple che abbiamo scritto noi stessi con l'implementazione .NET 4. Il nostro overdrle Tuple == per ottenere il comportamento che mi aspettavo nella domanda. Quindi sono rimasto sorpreso quando non si comportava esattamente come il nostro costume. –

risposta

13

I risultati che vedete provengono da un design compromise, tuple sono ora condiviso tra F # e C#. Il punto principale è che tutte le tuple sono effettivamente implementate come tipi di riferimento, che non era così ovvio.

La decisione se Tuples debba eseguire controlli di uguaglianza profondi o superficiali è stata spostata su due interfacce: IStructuralComparable, IStructuralEquatable. Nota che quelli 2 ora sono implementati anche dalla classe Array.

6

Per il tipo di riferimento: == esegue un confronto dell'identità, cioè restituirà true solo se entrambi i riferimenti puntano allo stesso oggetto. Mentre il metodo Equals() dovrebbe eseguire un confronto di valori, cioè restituirà true se i riferimenti puntano a oggetti che sono equivalenti.

Per i tipi di riferimento in cui ha == NON stato sovraccaricato, confronta se due riferimenti si riferiscono allo stesso oggetto

+3

Tranne la stringa che è magica. Quindi immagino di cercare più magia. Ti aspetteresti che una Tupla di tipi di valore esegua il controllo del valore? Non è così. –

+5

Non c'è magia: ha semplicemente sovraccaricato gli operatori == /! =; puoi vederlo in reflector come op_Equality e op_Inequality (su System.String). Ci ** è **, tuttavia, la magia su cose come 'int' /' float' (definite nelle specifiche) e 'Nullable ' (che utilizza operatori "sollevati"). –

+0

Non sono sicuro di comprendere appieno i tuoi commenti, la tua tupla nel tuo codice di esempio è un tipo di riferimento, non è vero? –

1

Per impostazione predefinita, l'operatore == test per l'uguaglianza di riferimento, in modo da il risultato che stanno vedendo è previsto.

Vedi Guidelines for Overriding Equals() and Operator == (C# Programming Guide):

In C#, ci sono due diversi tipi di uguaglianza: uguaglianza di riferimento (anche conosciuto come identità) e l'uguaglianza di valore. L'uguaglianza dei valori è generalmente il significato di uguaglianza compreso: significa che due oggetti contengono gli stessi valori . Ad esempio, due numeri interi con valore 2 hanno l'uguaglianza . L'uguaglianza di riferimento significa che non ci sono due oggetti a confronto .

1

Per impostazione predefinita, == (su una classe) indica l'uguaglianza di riferimento; cioè sono la stessa istanza; cosa restituirebbe object.ReferenceEquals(x,y).

È possibile fornire il proprio == /!= Gli operatori per ottenere il comportamento previsto - e quando si sostituisce Equals è importante per ignorare GetHashCode troppo (altrimenti si interrompe l'utilizzo come chiave - Why is it important to override GetHashCode when Equals method is overriden in C#?):

public static bool operator == (NameAndNumber x, NameAndNumber y) { 
    if (x == null && y == null) return true; 
    if (x == null || y == null) return false; 
    return x.Number == y.Number && x.Name == y.Name; 
    // or if polymorphism is important: return x.Equals(y); 
} 
public static bool operator !=(NameAndNumber x, NameAndNumber y) { 
    return !(x == y); // lazy but works 
} 
public override int GetHashCode() { 
    return (Name == null ? 0 : Name.GetHashCode()) + 
     17 * Number.GetHashCode(); 
} 
+1

Lo so. Come ho detto ho mostrato un'implementazione semplificata e ho lasciato GetHashCode per un esempio più piccolo. Ma questo non cambierà il modo in cui funziona Tuple e non posso aggiungerli a Tuple. Posso derivare da Tuple e aggiungerli. –

+1

Se il problema è il polimorfismo, quindi usa == '.Equals' - a parte questo ... questo è semplicemente come' == 'funziona. Se non lo sovraccarichi, non funzionerà in questo modo! –

+0

@Marc Gravell. Immagino che il cuore della domanda risieda nel caso in cui la classe Tuple integrata in .net 4.0 si comportasse in questo modo oppure no. Dovrebbe agire come un tipo di riferimento standard o delegare il controllo di uguaglianza agli oggetti che contiene? È solo un contenitore, quindi dovremmo preoccuparci se i due contenitori sono uguali o dovrebbero == controllare il contenuto dei contenitori. Questa non è la mia implementazione di Tuple, è quella integrata in .net 4. Le precedenti librerie di terze parti con un'implementazione Tuple o Pair sovrascrivevano == controllano l'uguaglianza degli oggetti contenuti. –

Problemi correlati