Какова «лучшая» каноническая реализация Equals() для ссылочных типов?

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

  •  09-06-2019
  •  | 
  •  

Вопрос

Реализация Equals() для ссылочных типов сложнее, чем кажется.Моя текущая каноническая реализация выглядит следующим образом:

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

Я думаю, что это охватывает все угловые случаи (наследование и тому подобное), но я могу ошибаться.Ребята, что вы думаете?

Это было полезно?

Решение

Некоторое время назад я написал довольно подробное руководство по этому вопросу.Для начала ваши реализации равных должны быть общими (т.перегрузка, принимающая объект, должна передаваться перегрузке, принимающей строго типизированный объект).Кроме того, вам необходимо учитывать такие вещи, как ваш объект, который должен быть неизменяемым из-за необходимости переопределить GetHashCode.Дополнительная информация здесь:

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

Другие советы

Лучше надеяться, что this._data не имеет значения null, если это также ссылочный тип.

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

Что касается наследования, я думаю, вам следует просто позволить объектно-ориентированной парадигме творить чудеса.

В частности, GetType() check следует удалить, это может привести к нарушению полиморфизма в дальнейшем.

Я согласен с чакритом, объекты разных типов должны быть семантически равными, если они имеют одинаковые данные или идентификатор.

Лично я использую следующее:

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

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

Это зависит от того, пишете ли вы тип значения или ссылочный тип.Для сортируемого типа значения я рекомендую следующее:Фрагмент кода для Visual Studio 2005, реализующий скелетный тип значения, соответствующий рекомендациям по проектированию Framework.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top