2009-09-27 6 views
14

Je vois un comportement différent entre l'utilisation de .Equals et == entre deux nouvelles instances Tuple <> de .NET 4.0. Si j'ai remplacé Equals sur l'objet dans le Tuple <> et appelez .Equals sur les Tuples, le remplacement de Equals sera appelé. Si j'utilise == sur les Tuples, le remplacement de Equals n'est pas appelé. Est-ce par conception et cela a-t-il un sens?Est-ce un comportement d'égalité Tuple C# 4.0 attendu?

EDIT: De réponses et de commentaires Je peux dire que je ne suis pas clair. Je sais que Tuple <> est un type de référence et que pour les types de référence == vérifiera l'identité (ReferenceEquals). Mais, est-ce que Tuple <> override == pour vérifier l'égalité des objets qu'il contient? Pour la cohérence, probablement pas.

Par exemple, si j'ai un simple objet

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; 
    } 
} 

puis-je faire quelque chose comme ceci:

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); 

Je reçois operatorResult = false equalsResult = true

Dois-je me attend cette?

Je sais que l'implémentation de Equals sur NameAndNumber n'est pas "correcte" mais simplement un exemple de code simplifié.

J'ai également essayé d'implémenter IEquatable, ==,! =, Et GetHashCode. Mêmes résultats

+0

Merci pour les réponses et les commentaires. J'aurais dû m'attendre à ce comportement. Je remplace nos projets 3.5 implémentation de Tuple nous nous sommes écrit avec l'implémentation de .NET 4. Notre Tuple a dépassé == pour obtenir le comportement que j'attendais dans la question. J'ai donc été surpris quand il ne se comportait pas exactement comme notre coutume. –

Répondre

13

Les résultats que vous voyez Venues d'une design compromise, Tuples sont maintenant partagé entre F # et C#. Le point principal est que tous les Tuples sont effectivement implémentés comme types de référence, ce qui n'était pas si évident.

La décision selon laquelle Tuples doit effectuer des vérifications d'égalité profondes ou superficielles a été déplacée vers deux interfaces: IStructuralComparable, IStructuralEquatable. Notez que ces 2 sont maintenant également implémentés par la classe Array.

6

Pour le type de référence: == effectue une comparaison d'identité, c'est-à-dire qu'il ne retournera vrai que si les deux références pointent vers le même objet. Alors que la méthode Equals() est supposée effectuer une comparaison de valeur, c'est-à-dire qu'elle retournera vrai si les références pointent vers des objets qui sont équivalents.

Pour les types de référence où == a pas été surchargée, il se compare si deux références se réfèrent au même objet

+3

Sauf pour la chaîne qui est magique. Donc je suppose que je cherche plus de magie. Souhaitez-vous vous attendre à ce qu'un Tuple de types de valeur fasse une vérification de valeur? Ce n'est pas le cas. –

+5

Il n'y a pas de magie - il a simplement surchargé == /! = Opérateurs; vous pouvez voir ceci dans le réflecteur comme op_Equality et op_Inequality (sur System.String). Il y a **, cependant, de la magie sur des choses comme 'int' /' float' (défini dans la spécification) et 'Nullable ' (qui utilise des opérateurs "levés"). –

+0

Je ne suis pas sûr de bien comprendre vos commentaires, votre Tuple dans votre exemple de code est un type de référence, n'est-ce pas? –

1

Par défaut, l'opérateur des tests == pour l'égalité de référence, de sorte Oui le résultat que vous voit est attendu.

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

En C#, il existe deux types différents de l'égalité: l'égalité de référence (également connue sous le nom identité) et l'égalité de valeur. Égalité de la valeur est généralement sens compris de l'égalité: il signifie que deux objets contiennent les mêmes valeurs . Par exemple, deux entiers avec la valeur 2 ont la valeur égalité. L'égalité de référence signifie qu'il n'y a pas deux objets à comparer.

1

Par défaut, == (sur une classe) signifie l'égalité de référence; c'est-à-dire sont-ils la même instance? ce que object.ReferenceEquals(x,y) reviendrait.

Vous pouvez fournir votre propre == /!= Opérateurs pour obtenir le comportement attendu - et quand vous substituez Equals il est important de passer outre GetHashCode aussi (sinon vous cassez l'utilisation comme clé - 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

Je sais. Comme je l'ai mentionné, j'ai montré une implémentation simplifiée et laissé GetHashCode pour un exemple plus petit. Mais cela ne changera pas le fonctionnement de Tuple et je ne peux pas les ajouter à Tuple. Je peux dériver de Tuple et les ajouter. –

+1

Si le polymorphisme est le problème, alors faites le == utiliser '.Equals' - autre que cela ... c'est simplement comment' == 'fonctionne. Si vous ne le surchargez pas, cela ne fonctionnera pas de cette façon! –

+0

@Marc Gravell. Je suppose que le cœur de la question réside dans le fait que la classe Tuple intégrée dans .net 4.0 se comporte de cette façon ou pas. Devrait-il agir comme un type de référence standard ou déléguer la vérification de l'égalité aux objets qu'il contient? C'est juste un conteneur, donc nous devrions nous soucier si les deux conteneurs sont les mêmes ou devraient == vérifier le contenu des conteneurs. Ce n'est pas mon implémentation de Tuple, c'est le built in .net 4 one. Les bibliothèques tierces précédentes avec une implémentation Tuple ou Pair remplaceront == vérifier l'égalité des objets contenus. –

Questions connexes