Qual é a “melhor” implementação canônica de Equals() para tipos de referência?

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

  •  09-06-2019
  •  | 
  •  

Pergunta

Implementar Equals() para tipos de referência é mais difícil do que parece.Minha implementação canônica atual é assim:

public bool Equals( MyClass obj )
{
  // If both refer to the same reference they are equal.
  if( ReferenceEquals( obj, this ) )
    return true;

  // If the other object is null they are not equal because in C# this cannot be null.
  if( ReferenceEquals( obj, null ) )
   return false;

   // Compare data to evaluate equality    
   return _data.Equals( obj._data );
}

public override bool Equals( object obj )
{
  // If both refer to the same reference they are equal.
  if( ReferenceEquals( obj, this ) )
    return true;

  // If the other object is null or is of a different types the objects are not equal. 
  if( ReferenceEquals( obj, null ) || obj.GetType() != GetType() )
    return false;

  // Use type-safe equality comparison
  return Equals( (MyClass)obj );
}

public override int GetHashCode()
{
  // Use data's hash code as our hashcode  
  return _data.GetHashCode();
}

Acho que isso cobre todos os casos (herança e outros), mas posso estar errado.O que é que vocês acham?

Foi útil?

Solução

Escrevi um guia bastante abrangente sobre isso há algum tempo.Para começar, suas implementações iguais devem ser compartilhadas (ou seja,a sobrecarga que recebe um objeto deve passar para aquela que recebe um objeto fortemente digitado).Além disso, você precisa considerar que coisas como seu objeto devem ser imutáveis ​​devido à necessidade de substituir GetHashCode.Mais informações aqui:

http://gregbeech.com/blog/implementing-object-equality-in-dotnet

Outras dicas

É melhor esperar que this._data não seja nulo se também for um tipo de referência.

public bool Equals( MyClass obj )
{
    if (obj == null) {
        return false;
    }
    else {
        return (this._data != null && this._data.Equals( obj._data ))
                         || obj._data == null;
    }
}

public override bool Equals( object obj )
{
    if (obj == null || !(obj is MyClass)) {
        return false;
    }
    else {
        return this.Equals( (MyClass)obj );
    }
}

public override int GetHashCode() {
    return this._data == null ? 0 : this._data.GetHashCode();
}

Com relação à herança, acho que você deveria deixar o paradigma OO fazer sua mágica.

Especificamente, o GetType() check deve ser removido, isso pode quebrar o polimorfismo no futuro.

Concordo com chakrit, objetos de tipos diferentes devem ser semanticamente iguais se tiverem os mesmos dados ou ID.

Pessoalmente, eu uso o seguinte:

    public override bool Equals(object obj)
    {
        var other = obj as MyClass;
        if (other == null) return false;

        return this.data.Equals(other.data);
    }

Depende se você está escrevendo um tipo de valor ou um tipo de referência.Para um tipo de valor classificável, recomendo isto:Um trecho de código para Visual Studio 2005 que implementa um tipo de valor esqueleto em conformidade com as Diretrizes de Design da Estrutura

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