2010-11-22 15 views
0

Ich versuche, eine eindeutige List<Author> geben eine List<BlogPost>, wobei jede BlogPost hat eine Author Eigenschaft. Ich habe die Erweiterungsmethode Distinct() in Generika gefunden und versuche sie zu verwenden. Lassen Sie mich zuerst meinen Loop erklären und wo ich ihn verwenden möchte, dann werde ich meinen Unterricht erklären und wo ich Probleme habe.Abstrakt eine IEqualityComparer-Implementierung oder überschreiben den Standardvergleich zu Distinct-Methode verwenden

deutlichen Versuch, hier zu verwenden

public List<Author> GetAuthors() { 

    List<BlogPost> posts = GetBlogPosts(); 
    var authors = new List<Author>(); 

    foreach (var bp in posts) { 
    authors.Add(bp.Author); 
    } 

    return authors.Distinct().ToList(); 
} 

Nach dem, was ich habe read on MSDN, Distinct() entweder verwendet den Standardvergleich oder ein in comparer geben. Ich hatte gehofft (ich weiß natürlich nicht, ob das machbar ist), einen Vergleicher an einer Stelle zu schreiben und ihn für alle meine Klassen zu verwenden, da sie alle nach der gleichen Gleichheitsoperation (die die GUID Eigenschaft von jede Klasse).

Alle meine Klassen erben von der BasePage Klasse:

public class BasePage : System.Web.UI.Page, IBaseTemplate, IEquatable<IBaseTemplate>, IEqualityComparer<IBaseTemplate> 

public class Author : BasePage 

public class BlogPost : BasePage 

Mein gleich implementiertes Verfahren in BasePage die GUID Eigenschaft vergleicht, die zu jeder einzigartig ist. Wenn ich Distinct() auf einem Author rufe, scheint es nicht zu funktionieren. Gibt es eine Möglichkeit, den Comparer an einem Ort einzupacken und immer in der Lage zu sein, ihn zu verwenden, anstatt etwas wie class AuhorComparer : IEqualityComparer<Auhor> schreiben zu müssen, da ich dann für jede Klasse dasselbe schreiben müsste, jedes Mal, wenn ich Distinct() verwenden möchte . Oder kann ich den Standardvergleich irgendwie überschreiben, also muss ich nichts an Distinct() weiterleiten?

Antwort

2

Die Distinct Operation ist wahrscheinlich nicht die beste Lösung hier, weil Sie am Ende eine potenziell sehr große Liste mit Duplikaten erstellen, nur um dann sofort zu verschiedenen Elementen zu verkleinern. Es ist wahrscheinlich besser, einfach mit HashSet<Author> zu beginnen, um die große Liste zu vermeiden.

public List<Author> GetAuthors() { 
    HashSet<Author> authorSet = new HashSet<Author>(); 
    foreach (var author in GetBlogPosts().Select(x => x.Author)) { 
    authorSet.Add(author); 
    } 
    return authorSet.ToList(); 
} 

Wenn Sie Distinct dann die beste Route benutzen wollen ist IEquatable auf dem Author Typ zu implementieren. Wenn keine explizite IEqualityComparer die Distinct und andere LINQ-Methoden geben wird schließlich in die Verwendung der IEquatable Implementierung auf den Typ. Normalerweise durch EqualityComprare<T>.Default

+0

Danke für den HashSet-Vorschlag. Ich habe Ihre Änderung implementiert, aber ich bekomme immer noch eine Liste in derselben Größe. Ich habe eine Liste 3 von Beiträgen, zwei haben den gleichen Autor, einer hat einen völlig anderen Autor. Ich bekomme jedoch eine Liste von 3 Autoren. –

+0

Beweist die Tatsache, dass das HashSet den gleichen Autor mehr als einmal enthält, dass meine Methoden Equals und GetHashCode falsch geschrieben sind? –

+0

Ich habe bestätigt, dass dies nicht funktioniert hat, weil meine 'GetHashCode' Methode nicht korrekt geschrieben wurde. Jetzt habe ich diesen Ansatz mit dem 'HashSet' funktioniert. Vielen Dank! –

0

Overriden Equals sollte für Sie arbeiten. Eine Sache, die schief gehen kann, ist, dass GetHashCode nicht mit Equals überschrieben wird, was die Framework-Richtlinien vorgeben sollten.

0

Der Code zeigt nur die Hauptidee, die, ich hoffe, wird nützlich sein.

public class Repository 
{ 
    public List<Author> GetAuthors() 
    { 
     var authors = new List<Author> 
         { 
          new Author{Name = "Author 1"}, 
          new Author{Name = "Author 2"}, 
          new Author{Name = "Author 1"} 
         }; 
     return authors.Distinct(new CustomComparer<Author>()).ToList(); 
    } 

    public List<BlogPost> GetBlogPosts() 
    { 
     var blogPosts = new List<BlogPost> 
     { 
      new BlogPost {Text = "Text 1"}, 
      new BlogPost {Text = "Text 2"}, 
      new BlogPost {Text = "Text 1"} 
     }; 
     return blogPosts.Distinct(new CustomComparer<BlogPost>()).ToList(); 
    } 
} 

//This comparer is required only one. 
public class CustomComparer<T> : IEqualityComparer<T> where T : class 
{ 
    public bool Equals(T x, T y) 
    { 
     if (y == null && x == null) 
     { 
      return true; 
     } 
     if (y == null || x == null) 
     { 
      return false; 
     } 
     if (x is Author && y is Author) 
     { 
      return ((Author)(object)x).Name == ((Author)(object)y).Name; 
     } 
     if (x is BlogPost && y is BlogPost) 
     { 
      return ((BlogPost)(object)x).Text == ((BlogPost)(object)y).Text; 
     } 
     //for next class add comparing logic here 
     return false; 
    } 

    public int GetHashCode(T obj) 
    { 
     return 0; // actual generating hash code should be here 
    } 
} 

public class Author 
{ 
    public string Name { get; set; } 
} 

public class BlogPost 
{ 
    public string Text { get; set; } 
}