¿Cuál es la "mejor" implementación canónica de Equals() para tipos de referencia?

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

  •  09-06-2019
  •  | 
  •  

Pregunta

Implementar Equals() para tipos de referencia es más difícil de lo que parece.Mi implementación canónica actual es la siguiente:

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

Creo que esto cubre todos los casos extremos (herencia y demás), pero puedo estar equivocado.¿Qué piensan ustedes?

¿Fue útil?

Solución

Escribí una guía bastante completa sobre esto hace un tiempo.Para empezar, sus implementaciones iguales deben compartirse (es decir,la sobrecarga que toma un objeto debe pasar a la que toma un objeto fuertemente tipado).Además, debe considerar cosas como que su objeto debe ser inmutable debido a la necesidad de anular GetHashCode.Más información aquí:

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

Otros consejos

Es mejor esperar que this._data no sea nulo si también es un tipo de referencia.

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

En cuanto a la herencia, creo que deberías dejar que el paradigma OO haga su magia.

Específicamente, el GetType() La verificación debe eliminarse, podría romper el polimorfismo en el futuro.

Estoy de acuerdo con chakrit, se debe permitir que objetos de diferentes tipos sean semánticamente iguales si tienen los mismos datos o ID.

Personalmente, uso lo siguiente:

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

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

Depende de si estás escribiendo un tipo de valor o un tipo de referencia.Para un tipo de valor ordenable, recomiendo esto:Un fragmento de código para Visual Studio 2005 que implementa un tipo de valor esqueleto que cumple con las pautas de diseño del marco.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top