Pergunta

Aqui está o que estou tentando fazer. Eu estou consultando um arquivo XML usando LINQ to XML, o que me dá uma IEnumerable<T> objeto, onde T é a minha classe "Village", preenchido com os resultados desta consulta. Alguns resultados são duplicados, então eu gostaria de realizar um distinto () no objeto IEnumerable, assim:

public IEnumerable<Village> GetAllAlliances()
{
    try
    {
        IEnumerable<Village> alliances =
             from alliance in xmlDoc.Elements("Village")
             where alliance.Element("AllianceName").Value != String.Empty
             orderby alliance.Element("AllianceName").Value
             select new Village
             {
                 AllianceName = alliance.Element("AllianceName").Value
             };

        // TODO: make it work...
        return alliances.Distinct(new AllianceComparer());
    }
    catch (Exception ex)
    {
        throw new Exception("GetAllAlliances", ex);
    }
}

Como o comparador padrão não funcionaria para o objeto Village, eu implementei um costume, como visto aqui na classe AllianceComparer:

public class AllianceComparer : IEqualityComparer<Village>
{
    #region IEqualityComparer<Village> Members
    bool IEqualityComparer<Village>.Equals(Village x, Village y)
    {
        // Check whether the compared objects reference the same data.
        if (Object.ReferenceEquals(x, y)) 
            return true;

        // Check whether any of the compared objects is null.
        if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
            return false;

        return x.AllianceName == y.AllianceName;
    }

    int IEqualityComparer<Village>.GetHashCode(Village obj)
    {
        return obj.GetHashCode();
    }
    #endregion
}

O método distinto () não funciona, como eu tenho exatamente o mesmo número de resultados com ou sem ele. Outra coisa, e eu não sei se é geralmente possível, mas não posso passo para AllianceComparer.Equals () para ver o que poderia ser o problema.
Eu encontrei exemplos disso na internet, mas eu não consigo fazer o meu trabalho de implementação.

Felizmente, alguém aqui pode ver o que poderia estar errado aqui! Agradecemos antecipadamente!

Foi útil?

Solução

O problema é com o seu GetHashCode. Você deve alterá-lo para retornar o código de hash de AllianceName vez.

int IEqualityComparer<Village>.GetHashCode(Village obj)
{
    return obj.AllianceName.GetHashCode();
}

A coisa é, se Equals retornos true, os objetos devem ter o mesmo código de hash que não é o caso para Village objetos diferentes com o mesmo AllianceName. Desde Distinct funciona através da construção de uma tabela hash internamente, você vai acabar com objetos iguais que não vai ser combinados em tudo devido a diferentes códigos de hash.

Da mesma forma, para comparar dois arquivos, se o hash de dois arquivos não são os mesmos, você não precisa verificar os próprios arquivos em tudo. Eles ser diferente. Caso contrário, você vai continuar a verificar para ver se eles são realmente o mesmo ou não. Isso é exatamente o que a tabela hash que usa Distinct se comporta.

Outras dicas

return alliances.Select(v => v.AllianceName).Distinct();

Isso retornaria um IEnumerable<string> vez de IEnumerable<Village>.

Ou alterar a linha

return alliances.Distinct(new AllianceComparer());

para

return alliances.Select(v => v.AllianceName).Distinct();
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top