2009-10-25 14 views
8

ich die folgenden Klassen haben:LinQ verschieden mit benutzerdefinierten Vergleich lässt Duplikate

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 
} 

und ich bin mit dem folgenden Linq-Abfrage:

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

Aber die deutliche nicht tut, was ich will es tun, wie der folgende Code zeigt:

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

Bin ich das falsch verwendet? Warum werden sie nicht so verglichen, wie ich es vorschlage?

Edit:

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. Es gibt keine C# 3.5 (siehe http://stackoverflow.com/questions/247621/what-are-the-correct-version-numbers-for-c) – Vaccano

Antwort

10

Ihr Problem ist, dass Sie nicht IEqualityComparer richtig umgesetzt haben: Um die der Vergleich funktioniert, gibt folgende Formel wahr, wie es sollte zeigen.

Wenn Sie IEqualityComparer<T> implementieren, müssen Sie implementieren GetHashCode implementieren, damit zwei gleiche Objekte den gleichen Hashcode haben.

Andernfalls erhalten Sie falsches Verhalten, wie Sie hier sehen.

Sie sollten GetHashCode implementieren wie folgt: (mit freundlicher Genehmigung von this answer)

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

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

    return hash; 
} 

Sie müssen auch GetHashCode in SupplierCategory außer Kraft zu setzen, konsequent sein. Zum Beispiel:

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

Schließlich obwohl Sie nicht brauchen, sollten Sie wahrscheinlich Equals in SupplierCategory außer Kraft setzen und die Equals Methode, die Sie für IEquatable implementiert machen nennen.

4

Tatsächlich ist dieses Problem sogar in der Dokumentation abgedeckt: http://msdn.microsoft.com/en-us/library/bb338049.aspx.

+0

Sie meinen in der Community Content? – SLaks

+0

Nein, ich meine, dass die Dokumentation die Code-Beispiele in VB und C# enthält, die zeigen, wie man einen eigenen Vergleicher erstellt. Es zeigt auch, wie Sie GetHashCode- und Equals-Methoden überschreiben können. –

Verwandte Themen