Перегрузка оператора ==,! =, Equals

Я уже прошел через question

Я понимаю, что необходимо реализовать ==, != и Equals().

public class BOX
{
    double height, length, breadth;

    // this is first one '=='
    public static bool operator== (BOX obj1, BOX obj2)
    {
        return (obj1.length == obj2.length 
                    && obj1.breadth == obj2.breadth 
                    && obj1.height == obj2.height);
    }

    // this is second one '!='
    public static bool operator!= (BOX obj1, BOX obj2)
    {
        return !(obj1.length == obj2.length 
                    && obj1.breadth == obj2.breadth 
                    && obj1.height == obj2.height);
    }

    // this is third one 'Equals'
    public override bool Equals(BOX obj)
    {
        return (length == obj.length 
                    && breadth == obj.breadth 
                    && height == obj.height);
    }
}

Я предполагаю, что я правильно написал код, чтобы переопределить операторы ==, !=, Equals. Хотя, я получаю ошибки компиляции следующим образом.

'myNameSpace.BOX.Equals(myNameSpace.BOX)' is marked as an override 
but no suitable method found to override.

Итак, вопрос: как переопределить вышеперечисленные операторы и избавиться от этой ошибки?

Ответ 1

Я думаю, вы объявили метод Equals следующим образом:

public override bool Equals(BOX obj)

Поскольку метод object.Equals принимает объект, нет способа переопределить эту подпись. Вы должны переопределить его следующим образом:

public override bool Equals(object obj)

Если вам нужен безопасный тип Equals,, вы можете реализовать IEquatable<BOX>.

Ответ 2

Как сказал Selman22, вы переопределяете метод по умолчанию object.Equals, который принимает object obj, а не тип безопасного времени компиляции.

Чтобы это произошло, создайте свой тип IEquatable<Box>:

public class Box : IEquatable<Box>
{
    double height, length, breadth;

    public static bool operator ==(Box obj1, Box obj2)
    {
        if (ReferenceEquals(obj1, obj2))
        {
            return true;
        }

        if (ReferenceEquals(obj1, null))
        {
            return false;
        }
        if (ReferenceEquals(obj2, null))
        {
            return false;
        }

        return (obj1.length == obj2.length
                && obj1.breadth == obj2.breadth
                && obj1.height == obj2.height);
    }

    // this is second one '!='
    public static bool operator !=(Box obj1, Box obj2)
    {
        return !(obj1 == obj2);
    }

    public bool Equals(Box other)
    {
        if (ReferenceEquals(null, other))
        {
            return false;
        }
        if (ReferenceEquals(this, other))
        {
            return true;
        }

        return height.Equals(other.height) 
               && length.Equals(other.length) 
               && breadth.Equals(other.breadth);
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj))
        {
            return false;
        }
        if (ReferenceEquals(this, obj))
        {
            return true;
        }

        return obj.GetType() == GetType() && Equals((Box)obj);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            int hashCode = height.GetHashCode();
            hashCode = (hashCode * 397) ^ length.GetHashCode();
            hashCode = (hashCode * 397) ^ breadth.GetHashCode();
            return hashCode;
        }
    }
}

Еще одна вещь, которую нужно отметить, это то, что вы делаете сравнение с плавающей точкой, используя оператор равенства, и вы можете потерять точность.

Ответ 3

На самом деле это тема "как". Итак, вот эталонная реализация:

    public class BOX
    {
        double height, length, breadth;

        public static bool operator == (BOX b1, BOX b2)
        {
            if ((object)b1 == null)
                return (object)b2 == null;

            return b1.Equals(b2);
        }

        public static bool operator != (BOX b1, BOX b2)
        {
            return !(b1 == b2);
        }

        public override bool Equals(object obj)
        {
            if (obj == null || GetType() != obj.GetType())
                return false;

            var b2 = (BOX)obj;
            return (length == b2.length && breadth == b2.breadth && height == b2.height);
        }

        public override int GetHashCode()
        {
            return height.GetHashCode() ^ length.GetHashCode() ^ breadth.GetHashCode();
        }
    }

REF: https://msdn.microsoft.com/en-us/library/336aedhh(v=vs.100).aspx#Examples

ОБНОВЛЕНИЕ: приведение к (object) в реализации operator == важно, в противном случае, оно будет повторно выполнять перегрузку оператора ==, что приведет к переполнению стека. Кредиты на @grek40.

Этот трюк (object) от Microsoft String == реализация. SRC: https://github.com/Microsoft/referencesource/blob/master/mscorlib/system/string.cs#L643