Наиболее надежная реализация Equals для пользовательских классов для равенства значений в C#

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

  •  05-09-2019
  •  | 
  •  

Вопрос

Допустим, у меня есть класс Point2, и я хочу реализовать следующие Equals:

public override bool Equals ( object obj )

public bool Equals ( Point2 obj )

Это взято из книги "Эффективный C # 3":

public override bool Equals ( object obj )
{
    // STEP 1: Check for null
    if ( obj == null )
    {
        return false;
    }

    // STEP 3: equivalent data types
    if ( this.GetType ( ) != obj.GetType ( ) )
    {
        return false;
    }
    return Equals ( ( Point2 ) obj );
}

public bool Equals ( Point2 obj )
{
    // STEP 1: Check for null if nullable (e.g., a reference type)
    if ( obj == null )
    {
        return false;
    }
    // STEP 2: Check for ReferenceEquals if this is a reference type
    if ( ReferenceEquals ( this, obj ) )
    {
        return true;
    }
    // STEP 4: Possibly check for equivalent hash codes
    if ( this.GetHashCode ( ) != obj.GetHashCode ( ) )
    {
        return false;
    }
    // STEP 5: Check base.Equals if base overrides Equals()
    System.Diagnostics.Debug.Assert (
        base.GetType ( ) != typeof ( object ) );

    if ( !base.Equals ( obj ) )
    {
        return false;
    }

    // STEP 6: Compare identifying fields for equality.
    return ( ( this.X.Equals ( obj.X ) ) && ( this.Y.Equals ( obj.Y ) ) );
}

Это что, перебор?

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

Решение

Поддерживать равенство с помощью иерархии наследования непросто.Вам нужно точно определить, что вы имеете в виду.Вам действительно нужно здесь наследование?Если нет - если Point2 выводится непосредственно из System.Объект, и вы можете сделать его запечатанным, жизнь становится немного проще.В этом случае я бы использовал:

public override bool Equals (object obj)
{
    return Equals(obj as Point2);
}

public bool Equals (Point2 obj)
{
    // STEP 1: Check for null if nullable (e.g., a reference type)
    // Note use of ReferenceEquals in case you overload ==.
    if (object.ReferenceEquals(obj, null))
    {
        return false;
    }

    // STEP 2: Check for ReferenceEquals if this is a reference type
    // Skip this or not? With only two fields to check, it's probably
    // not worth it. If the later checks are costly, it could be.
    if (object.ReferenceEquals( this, obj))
    {
        return true;
    }

    // STEP 4: Possibly check for equivalent hash codes
    // Skipped in this case: would be *less* efficient

    // STEP 5: Check base.Equals if base overrides Equals()
    // Skipped in this case

    // STEP 6: Compare identifying fields for equality.
    // In this case I'm using == instead of Equals for brevity
    // - assuming X and Y are of a type which overloads ==.
    return this.X == obj.X && this.Y == obj.Y;
}

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

Не совсем - вы учитываете практически все возможности.Если этот код предназначен для чего-либо другого, кроме приложения scratch, вам следует рассмотреть преимущества такого подхода, потому что логические ошибки из-за странного поведения равенства объектов болезненны для отладки.

По-моему, это именно то, чего бы ты хотел.Весь этот квартал сводится к:

"если это точно такой же экземпляр, верните true.Если это отдельные экземпляры с одинаковыми значениями X и Y, верните true .Все остальные случаи (null, другой тип, разные значения x / y) возвращают false."

Это, безусловно, больше кода, чем Я бы хочу написать для метода equals .Существует множество избыточных проверок, таких как проверка на наличие ReferenceEquals и хэш-кодов (я знаю, что эти проверки избыточны, потому что последние строки в вашей функции проверяют структурное равенство).Сосредоточьтесь на простом и читабельном коде.

public bool Equals(object o)
{
    Point2 p = o as Point2;
    if (o != null)
        return this.X == o.X && this.Y == o.Y;
    else
        return false;
}

Поскольку ваш метод equals использует структурное равенство, убедитесь, что вы переопределяете GetHashCode реализацией, основанной также на ваших полях.

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