È questo un comportamento previsto uguaglianza C # 4.0 Tuple?
Domanda
sto vedendo un comportamento diverso tra l'utilizzo .equals e == tra due di .NET 4.0 di nuova tupla <> istanze. Se ho sovrascritto Uguale sull'oggetto nel Tuple <> e chiamare .equals sul tuple sarà chiamato l'override di Equals. Se uso == sul Tuples l'override di Equals non è chiamato. È che la progettazione e ha senso?
Modifica Da risposte e commenti posso dire io non sono chiari. So Tuple <> è un tipo di riferimento e che per i tipi di riferimento == controllerà l'identità (ReferenceEquals). Ma, dovrebbe Tuple <> di override == per verificare l'uguaglianza degli oggetti in esso contenuti? 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);
ho operatorResult = false equalsResult = true
Dovrei essere aspettavo?
So che l'attuazione degli Eguali su NameAndNumber non è "giusto" codice di esempio è solo semplificata.
Ho anche provato attuazione IEquatable, ==,! =, E GetHashCode. Stessi risultati.
Soluzione
I risultati che vedete provengono da una progettazione compromesso , tuple sono ora condivisa tra F # e C #. L'importante è che tutte le tuple siano effettivamente implementati come tipi di riferimento, che non era così evidente.
La decisione se tuple dovrebbe fare controlli di uguaglianza profonde o poco profonde è stato spostato a due interfacce: IStructuralComparable
, IStructuralEquatable
. Si noti che quei 2 sono ora implementate anche dalla classe Array.
Altri suggerimenti
Per il tipo di riferimento: == esegue un confronto di identità, cioè tornerà vera solo se entrambi i riferimenti puntano allo stesso oggetto. Mentre si prevede che Equals () per eseguire un confronto valore, cioè esso restituisce true se i riferimenti indicano oggetti equivalenti.
Per i tipi di riferimento in cui == ha non stato sovraccaricato, confronta se due riferimenti si riferiscono allo stesso oggetto
Per impostazione predefinita, l'operatore == test per l'uguaglianza di riferimento, per cui Sì il risultato che state vedendo è previsto.
per escludere Equals Vedere Linee Guida () e Operatore == (Guida per programmatori C # ) :
In C #, ci sono due tipi differenti di uguaglianza: uguaglianza riferimento (anche noto come l'identità) e l'uguaglianza di valore. uguaglianza valore è il genere capito significato di uguaglianza: è significa che due oggetti contengono la valori stessi. Ad esempio, due interi con il valore di 2 hanno valore uguaglianza. mezzi di uguaglianza di riferimento che non vi sono due oggetti a confrontare.
Per impostazione predefinita, ==
(su una classe) significa uguaglianza di riferimento; cioè essi sono lo stesso grado; ciò object.ReferenceEquals(x,y)
sarebbero tornati.
È possibile fornire il proprio == / = operatori per ottenere il comportamento previsto - e quando si sostituisce Equals
è importante ignorare GetHashCode
troppo (altrimenti si romperà l'utilizzo come chiave - Why è importante ignorare GetHashCode quando Equals metodo viene sovrascritto 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();
}