Resumo uma implementação de conformidade ou substituição do comparador padrão para usar o método distinto

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

Pergunta

Estou tentando encontrar um distinto List<Author> dado a List<BlogPost> onde cada um BlogPost tem um Author propriedade. Eu encontrei o Distinct() Método de extensão em genéricos e estou tentando usá -lo. Primeiro, deixe -me explicar meu loop e onde quero usá -lo, depois explicarei minhas aulas e onde estou tendo problemas.

Tentando usar distintos aqui

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

Baseado no que eu Leia no MSDN, Distinct() ou usa o comparador padrão ou um passado no comparador. Eu esperava (eu obviamente não sei se isso é factível) para escrever uma comparação em um ponto e ser capaz de usá -lo para todas as minhas aulas, pois todas elas se comparam exatamente pela mesma operação de igualdade (que compara o GUID propriedade de cada classe).

Todas as minhas aulas herdam do BasePage classe:

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

public class Author : BasePage

public class BlogPost : BasePage

Meu método igual a ser implementado em BasePage compara o GUID propriedade exclusiva para cada um. Quando eu ligo Distinct() em um Author Não parece funcionar. Existe alguma maneira de encerrar o comparador em um só lugar e sempre ser capaz de usá -lo, em vez de ter que escrever algo como class AuhorComparer : IEqualityComparer<Auhor> Como eu precisava escrever a mesma coisa para cada aula, toda vez que eu quiser usar Distinct(). Ou Posso substituir o comparador padrão de alguma forma, então não tenho que passar nada para Distinct()?

Foi útil?

Solução

o Distinct A operação provavelmente não é a melhor solução aqui, porque você acaba construindo uma lista potencialmente muito grande, com duplicatas apenas para encolher imediatamente para elementos distintos. Provavelmente é melhor apenas começar com um HashSet<Author> Para evitar construir a grande lista.

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

Se você quiser usar Distinct então o melhor caminho é implementar IEquatable no Author modelo. Quando não recebeu um explícito IEqualityComparer a Distinct e outros métodos LINQ acabarão por usar o uso do IEquatable implementação no tipo. Geralmente através EqualityComprare<T>.Default

Outras dicas

Overiden iguais deve funcionar para você. Uma coisa que pode estar dando errado é que o GethashCode não é substituído ao lado de iguais, que as diretrizes da estrutura ditam.

O código mostra apenas a idéia principal, que, espero, será útil.

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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top