2017-01-05 2 views
2

Consultez le code suivant, où ClassOne est une classe dérivée de IClass:C# - opérateur d'égalité avec la liste de type d'interface ne fonctionne pas comme prévu

List<IClass> list = new List<IClass>(); 
list.Add(new ClassOne("foo", "bar")); 
list.Add(new ClassOne("baz", "bam")); 

List<IClass> list2 = new List<IClass>(); 
list2.Add(new ClassOne("foo", "bar")); 
list2.Add(new ClassOne("baz", "bam")); 

if (list == list2) 
    Console.WriteLine("Lists are equal."); 
else 
    Console.WriteLine("Lists are NOT equal."); 

L'opérateur d'égalité renvoie false (c.-à-listes ne correspondent pas), outre le fait que le operator ==, operator !=, Equals(ClassOne), Equals(object) et GetHashCode() ont été mis en œuvre/remplacé pour ClassOne. Pourquoi donc? Je m'attendrais à ce que l'opérateur d'égalité revienne vrai. Existe-t-il d'autres méthodes/interfaces qui doivent être implémentées pour que l'opérateur == fonctionne comme prévu?

Pour référence, voici la mise en œuvre de ClassOne et IClass:

public interface IClass 
{ 
    string getA(); 
    string getB(); 
} //interface 


public class ClassOne : IClass, IEquatable<ClassOne> 
{ 
    public ClassOne(string a, string b) 
    { 
     strA = a; 
     strB = b; 
    } 

    public string getA() 
    { 
     return strA; 
    } 

    public string getB() 
    { 
     return strB; 
    } 

    public bool Equals(ClassOne other) 
    { 
     if (ReferenceEquals(null, other)) return false; 
     if (ReferenceEquals(this, other)) return true; 
     if (!string.Equals(strA, other.strA)) 
      return false; 
     return string.Equals(strB, other.strB); 
    } 

    public override bool Equals(object other) 
    { 
     if (ReferenceEquals(null, other)) return false; 
     if (ReferenceEquals(this, other)) return true; 
     if (other is ClassOne) 
     { 
      ClassOne c1 = (ClassOne)other; 
      return Equals(c1); 
     } 
     //not ClassOne, so it is not equal 
     return false; 
    } 

    public override int GetHashCode() 
    { 
     int hc_a = -1; 
     if (null != strA) 
      hc_a = strA.GetHashCode(); 
     int hc_b = -1; 
     if (null != strB) 
      hc_b = strB.GetHashCode(); 
     return hc_a^hc_b; 
    } 

    public static bool operator ==(ClassOne left, ClassOne right) 
    { 
     if (ReferenceEquals(left, right)) return true; 
     if (ReferenceEquals(left, null) || ReferenceEquals(right, null)) 
      return false; 
     return left.Equals(right); 
    } 

    public static bool operator !=(ClassOne left, ClassOne right) 
    { 
     return !(left == right); 
    } 

    private string strA, strB; 
} //class 

Toute aide ou des conseils dans la bonne direction seront appréciés. Merci.

Répondre

8

Pourquoi est-ce? Je m'attendrais à ce que l'opérateur d'égalité revienne vrai.

Non correct - l'opérateur == (et Equals()) ne sont pas définis sur List<T> pour vérifier l'égalité de son contenu - il est par défaut de référencer l'égalité de l'opérateur défini sur object. Puisque les deux listes sont des objets différents, == renvoie false.

Vous pouvez utiliser la méthode Linq SequenceEqual pour déterminer si deux listes contiennent des objets égaux dans le même ordre:

if (list.SequenceEqual(list2)) 
    Console.WriteLine("Lists are equal."); 
else 
    Console.WriteLine("Lists are NOT equal."); 
+0

C'est mauvais. Donc, je dois utiliser 'list.Equals (list2)' chaque fois que je veux vérifier le contenu des listes pour l'égalité? – Striezel

+4

Non. 'Equals' n'est pas surchargé non plus. Vous auriez besoin d'utiliser 'SequenceEquals' de Linq ou d'un autre mécanisme. –

3

Parce que l'opérateur == n'est pas surchargé pour la classe List<T>. == pour les listes est simplement l'égalité de référence. Même deux List<int> objets qui détiennent les mêmes int s ne sont pas égaux, etc.

Si vous demandez si list == list2, le compilateur appellera l'opérateur == pour List<T>, et le concepteur de la classe List<T> ont décidé que deux listes ne sont égal si les deux se réfèrent à la même liste. En d'autres termes:

public class List<T> { 

    public static bool operator ==(List<T> left, List<T> right) { 
     return ReferenceEquals(left, right); 
    } 

} 

(Evidemment il y a plus de contenu dans la classe List<T>, et comme il utilise l'égalité de référence, on ne pas surcharger ont l'opérateur).

+0

Eh bien, 'List ' ne définit pas du tout l'opérateur, donc l'opérateur sur 'object' est utilisé. Bien que votre exemple illustre cela, le code n'est pas réellement écrit de cette façon. –

+0

@DStanley: entre parenthèses je dis que: vous n'avez en effet pas à surcharger l'opérateur. C'est simplement pour montrer * explicitement * pourquoi la liste ne vérifie pas l'égalité des éléments. –