implementación abstracta de un IEqualityComparer o anular el comparador predeterminado para utilizar el método distinto

StackOverflow https://stackoverflow.com/questions/4250381

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

¿Fue útil?

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; }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top