2009-10-25 4 views
8

Tengo las siguientes clases:LinQ distinta con el comparador de encargo deja duplicados

public class SupplierCategory : IEquatable<SupplierCategory> 
{ 
    public string Name { get; set; } 
    public string Parent { get; set; } 

    #region IEquatable<SupplierCategory> Members 

    public bool Equals(SupplierCategory other) 
    { 
     return this.Name == other.Name && this.Parent == other.Parent; 
    } 

    #endregion 
} 

public class CategoryPathComparer : IEqualityComparer<List<SupplierCategory>> 
{ 
    #region IEqualityComparer<List<SupplierCategory>> Members 

    public bool Equals(List<SupplierCategory> x, List<SupplierCategory> y) 
    { 
     return x.SequenceEqual(y); 
    } 

    public int GetHashCode(List<SupplierCategory> obj) 
    { 
     return obj.GetHashCode(); 
    } 

    #endregion 
} 

y estoy usando la siguiente consulta LINQ:

CategoryPathComparer comparer = new CategoryPathComparer(); 
List<List<SupplierCategory>> categoryPaths = (from i in infoList 
                  select 
                  new List<SupplierCategory>() { 
                  new SupplierCategory() { Name = i[3] }, 
                  new SupplierCategory() { Name = i[4], Parent = i[3] }, 
                  new SupplierCategory() { Name = i[5], Parent = i[4] }}).Distinct(comparer).ToList(); 

Pero la distintas no hace lo que yo quiero que haga, como lo demuestra el siguiente código:

comp.Equals(categoryPaths[0], categoryPaths[1]); //returns True 

¿Estoy usando esto de una manera incorrecta? ¿Por qué no se comparan como yo lo intento?

Editar: Para demostrar el trabajo que hace el comparador, las siguientes declaraciones de verdad como debe ser:

List<SupplierCategory> list1 = new List<SupplierCategory>() { 
    new SupplierCategory() { Name = "Cat1" }, 
    new SupplierCategory() { Name = "Cat2", Parent = "Cat1" }, 
    new SupplierCategory() { Name = "Cat3", Parent = "Cat2" } 
}; 
List<SupplierCategory> list1 = new List<SupplierCategory>() { 
    new SupplierCategory() { Name = "Cat1" }, 
    new SupplierCategory() { Name = "Cat2", Parent = "Cat1" }, 
    new SupplierCategory() { Name = "Cat3", Parent = "Cat2" } 
}; 
CategoryPathComparer comp = new CategoryPathComparer(); 
Console.WriteLine(comp.Equals(list1, list2).ToString()); 
+0

Retag. No hay C# 3.5 (vea http://stackoverflow.com/questions/247621/what-are-the-correct-version-numbers-for-c) – Vaccano

Respuesta

10

Su problema es que no se puso en práctica IEqualityComparer correctamente.

Cuando se implementa IEqualityComparer<T>, que debe aplicarGetHashCode de manera que dos objetos iguales tienen el mismo código hash.

De lo contrario, obtendrá un comportamiento incorrecto, como se ve aquí.

Debe implementar GetHashCode de la siguiente manera: (cortesía de this answer)

public int GetHashCode(List<SupplierCategory> obj) { 
    int hash = 17; 

    foreach(var value in obj) 
     hash = hash * 23 + obj.GetHashCode(); 

    return hash; 
} 

También es necesario para anular GetHashCode en SupplierCategory ser consistente. Por ejemplo:

public override int GetHashCode() { 
    int hash = 17; 
    hash = hash * 23 + Name.GetHashCode(); 
    hash = hash * 23 + Parent.GetHashCode(); 
    return hash; 
} 

Por último, aunque no es necesario, probablemente debería anular Equals en SupplierCategory y hacer que llamar al método Equals ha implementado para IEquatable.

4

En realidad, este problema está cubierto por la documentación: http://msdn.microsoft.com/en-us/library/bb338049.aspx.

+0

¿Quiere decir en el contenido de la comunidad? – SLaks

+0

No, me refiero a que la documentación contiene los ejemplos de código en VB y C# que muestran cómo crear su propio comparador. También muestra cómo puede anular los métodos GetHashCode y Equals. –

Cuestiones relacionadas