Pergunta

Basicamente, eu tenho o seguinte até agora:

class Foo {
    public override bool Equals(object obj)
    {
        Foo d = obj as Foo ;
        if (d == null)
            return false;

        return this.Equals(d);
    }

    #region IEquatable<Foo> Members

    public bool Equals(Foo other)
    {
        if (this.Guid != String.Empty && this.Guid == other.Guid)
            return true;
        else if (this.Guid != String.Empty || other.Guid != String.Empty)
            return false;

        if (this.Title == other.Title &&
            this.PublishDate == other.PublishDate &&
            this.Description == other.Description)
            return true;

        return false;
    }
}

Então, o problema é o seguinte: Eu tenho um Guid não-obrigatório Campo, que é um identificador exclusivo. Se isso não for definido, então eu preciso para tentar determinar a igualdade com base em métricas menos precisos como uma tentativa de determinar se dois objetos são iguais. Esta multa funciona, mas fazer GetHashCode() confuso ... Como devo ir sobre ele? A implementação ingênua seria algo como:

public override int GetHashCode() {
    if (this.Guid != String.Empty)
        return this.Guid.GetHashCode();

    int hash = 37;
    hash = hash * 23 + this.Title.GetHashCode();
    hash = hash * 23 + this.PublishDate.GetHashCode();
    hash = hash * 23 + this.Description.GetHashCode();
    return hash;
}

Mas quais são as chances dos dois tipos de colisão de hash? Certamente, eu não esperava que fosse 1 in 2 ** 32. É uma má idéia, e em caso afirmativo, como eu deveria estar fazendo isso?

Foi útil?

Solução

Eu não acho que há um problema com a abordagem que você escolheu para uso. Preocupar-se 'demasiado' sobre colisões de hash é quase sempre uma indicação de sobre-pensar o problema; enquanto o hash é altamente provável que seja diferente, você deve ser fino.

Em última análise, você pode até querer considerar deixando de fora o Description do seu hash de qualquer maneira se é razoável esperar que a maioria dos objetos de tempo podem ser distinguidos com base em seu título e data de publicação (livros?).

Você pode até considerar desconsiderando o GUID em sua função hash completamente, e só usá-lo na implementação Equals para disambiguate o improvável (?) Caso de confrontos hash.

Outras dicas

Um muito fácil método código hash para classes personalizadas é XOR bit a bit cada um dos códigos de hash campos juntos. Pode ser tão simples como isto:

int hash = 0;
hash ^= this.Title.GetHashCode();
hash ^= this.PublishDate.GetHashCode();
hash ^= this.Description.GetHashCode();
return hash;

A partir do link acima :

XOR tem as seguintes propriedades agradáveis:

  • Ele não depende de ordem de computação.
  • Não “desperdiçar” pedaços. Se você mudar até mesmo um pouco em um dos componentes, o valor final vai mudar.
  • É rápido, um único ciclo em até mesmo o computador mais primitivo.
  • Preserva distribuição uniforme. Se as duas peças que combinam são uniformemente distribuídas assim será a combinação ser. Em outras palavras, ele não tendem a entrar em colapso o alcance do digerir em uma faixa mais estreita.

XOR não funciona bem se você espera ter valores duplicados em seus campos como valores duplicados irá se anulam quando XORed. Desde que você está hashing juntos três campos não relacionados que não deve ser um problema neste caso.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top