implementación abstracta de un IEqualityComparer o anular el comparador predeterminado para utilizar el método distinto
-
27-09-2019 - |
Pregunta
Estoy tratando de encontrar un List<Author>
distinta dado un List<BlogPost>
donde cada uno tiene una propiedad BlogPost
Author
. He encontrado el método de extensión Distinct()
en genéricos y yo estoy tratando de usarlo. En primer lugar, permítanme explicar mi bucle y donde quiero usarlo, a continuación, voy a explicar mis clases y donde yo estoy teniendo problemas.
Tratar de utilizar distinta aquí
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();
}
Sobre la base de lo que he leído en MSDN , ya sea Distinct()
utiliza el comparador predeterminado o una aprobada en el comparador. Tenía la esperanza (I obviosuly No sé si esto es factible) para escribir un comparador en un lugar y ser capaz de utilizarlo para todas mis clases ya que todos ellos se comparan por la exacta misma operación la igualdad (que compara la propiedad de GUID
cada clase).
Todas mis clases heredan de la clase BasePage
:
public class BasePage : System.Web.UI.Page, IBaseTemplate, IEquatable<IBaseTemplate>, IEqualityComparer<IBaseTemplate>
public class Author : BasePage
public class BlogPost : BasePage
Mi equivale método implementado en BasePage
compara la propiedad GUID
que es único para cada uno. Cuando llamo Distinct()
en una Author
no parece al trabajo. ¿Hay alguna manera de que pueda concluir el comparador en un lugar y siempre será capaz de utilizarlo en lugar de tener que escribir algo como class AuhorComparer : IEqualityComparer<Auhor>
desde entonces que había necesidad de escribir el mismo para cada clase, cada vez que quiero usar Distinct()
. o ¿Puedo anular el comparador predeterminado de alguna manera, así que no tengo que pasar nada a Distinct()
?
Solución
La operación Distinct
probablemente no es la mejor solución, porque aquí se termina la construcción de una lista potencialmente muy grande con duplicados sólo para luego encoge inmediatamente a elementos distintos. Es probable que sea mejor empezar con un solo HashSet<Author>
para evitar la construcción de la lista grande.
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();
}
Si desea utilizar Distinct
entonces la mejor ruta para implementar IEquatable
del tipo Author
. Cuando no se da una IEqualityComparer
explícitamente los métodos Distinct
y otra LINQ con el tiempo por defecto en el uso de la aplicación del tipo IEquatable
. Por lo general, a través EqualityComprare<T>.Default
Otros consejos
Iguales overriden deben trabajar para usted. Una cosa que podría estar pasando mal es que GetHashCode no se anula junto con los iguales, que las directrices marco dictan que debe suceder.
El código sólo muestra la idea principal, que, espero, será de gran utilidad.
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; }
}