Abstrakt ein IEqualityComparer Implementierung oder den Standardvergleich außer Kraft setzen Distinct-Methode zu verwenden
-
27-09-2019 - |
Frage
Ich versuche, eine deutliche List<Author>
ein List<BlogPost>
gegeben zu finden, wo jeder BlogPost
eine Author
Eigenschaft hat. Ich habe die Distinct()
Erweiterungsmethode in den Bereichen Generika gefunden und ich versuche, es zu benutzen. Erstens, lassen Sie mich erklären meine Schleife und wo ich es benutzen wollen, dann werde ich meine Klassen erklären und wo ich habe Probleme.
Der Versuch, unterschiedliche verwenden hier
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 lesen auf MSDN , Distinct()
entweder verwendet den Standardvergleich oder ein in comparer geben. Ich hatte gehofft, (I obviosuly weiß nicht, ob dies machbar ist) einen Vergleich an einer Stelle zu schreiben und in der Lage sein, es für all meine Klassen zu verwenden, da sie alle von der exakt gleichen Gleichheit Vergleichsoperation (die die GUID
Eigenschaft vergleicht die 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
entspricht Meine Methode in BasePage
implementiert, um die GUID
Eigenschaft vergleicht, die zu jeder einzigartig ist. Als ich Distinct()
auf einem Author
nennen scheint es nicht zu arbeiten. Gibt es eine Möglichkeit, die comparer an einem Ort einpacken kann und immer in der Lage sein, es zu benutzen, anstatt wie class AuhorComparer : IEqualityComparer<Auhor>
zu schreiben etwas mit, da ich dann bräuchten, um die gleiche Sache für jede Klasse schreibt jedes Mal, ich will Distinct()
verwenden . oder kann ich den Standardvergleich irgendwie außer Kraft setzen, so muß ich nichts zu Distinct()
passieren?
Lösung
Die Distinct
Operation ist wahrscheinlich nicht die beste Lösung, weil man hier nur eine potenziell sehr große Liste mit Dubletten Gebäuden am Ende, um dann sofort schrumpfen sie verschiedene Elemente. Es ist wahrscheinlich besser, nur mit einem HashSet<Author>
zu beginnen, die großen Liste zu vermeiden aufzubauen.
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 verwenden möchten Distinct
tun, dann ist die beste Route IEquatable
auf dem Author
Typ zu implementieren. Wenn kein expliziten IEqualityComparer
der Distinct
und andere LINQ Methoden gegeben werden standardmäßig schließlich in der Art der IEquatable
Implementierung verwenden. In der Regel durch EqualityComprare<T>.Default
Andere Tipps
außer Kraft setzen Equals sollte für Sie arbeiten. Eine Sache, die schief gehen könnte, ist, dass GetHashCode nicht neben Equals überschrieben wird, die die Rahmenrichtlinien vorschreiben passieren sollte.
Der Code zeigt nur die Hauptidee, die, wie ich hoffe, nützlich sein wird.
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; }
}