Как переопределить оператор equals == для интерфейса в С#?

Я определил следующий интерфейс

public interface IHaveAProblem
{
    string Issue { get; set; }
}

И вот реализация IHaveAProblem

public class SomeProblem : IHaveAProblem
{
    public string Issue { get; set; }

    public override bool Equals(object obj)
    {
        SomeProblem otherObj = obj as SomeProblem;

        if (otherObj == null)
        {
            return false;
        }

        return this.Issue == otherObj.Issue;
    }

    public override int GetHashCode()
    {
        return base.GetHashCode();
    }

    public static bool operator ==(SomeProblem rhs, SomeProblem lhs)
    {
        // Null check
        if (Object.ReferenceEquals(rhs, null) || Object.ReferenceEquals(lhs, null))
        {
            if (Object.ReferenceEquals(rhs, null) && Object.ReferenceEquals(lhs, null))
            {
                // Both are null.  They do equal each other
                return true;
            }

            // Only 1 is null the other is not so they do not equal
            return false;
        }

        return rhs.Equals(lhs);
    }

    public static bool operator !=(SomeProblem rhs, SomeProblem lhs)
    {
        // Null check
        if (Object.ReferenceEquals(rhs, null) || Object.ReferenceEquals(lhs, null))
        {
            if (Object.ReferenceEquals(rhs, null) && Object.ReferenceEquals(lhs, null))
            {
                // Both are null.  They do equal each other
                return false;
            }

            // Only 1 is null the other is not so they do not equal
            return true;
        }

        return !rhs.Equals(lhs);
    }
}

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

SomeProblem firstTest = new SomeProblem()
    {
        Issue = "Hello World"
    };

SomeProblem secondTest = new SomeProblem()
    {
        Issue = "Hello World"
    };

// This is true
bool result = firstTest == secondTest;

Однако, когда я пытаюсь сравнить интерфейсы, он выполняет сравнение памяти, а не оператор == на SomeProblem

IHaveAProblem firstProblem = new SomeProblem()
    {
        Issue = "Hello World"
    };

IHaveAProblem secondProblem = new SomeProblem()
    {
        Issue = "Hello World"
    };

Возможно ли, что интерфейс использует == на SomeProblem, а не сравнение с памятью?

Я знаю, что могу сделать firstProblem.Equals(secondProblem) и получить правильный результат, однако я создаю фреймворк, и я не буду знать, как он используется в конце. Я думал, что == будет работать правильно.

Ответы

Ответ 1

Оператор == является статическим. Вы не можете определить статические методы для интерфейсов в С#. Кроме того, для всех операторов хотя бы один из типов аргументов должен быть того же типа, что и класс, в котором он определен, поэтому: Нет перегрузки оператора для интерфейсов: (

Что вы можете сделать, так это использовать абстрактный класс - и определить там оператор. Опять же, оператор НЕ может быть виртуальным (поскольку статические методы не могут быть виртуальными...)

[Отредактировано, причина см. комментарий.]

Ответ 2

IIRC (и я могу ошибаться здесь), интерфейсы С# не позволяют перегрузке оператора.

Но в этом случае все в порядке. Оператор == обычно отображается на ссылочное равенство. Похоже, вам нужно равенство ценности, и это означает, что вы хотите заставить их переопределить функции .Equals() (и, следовательно, также .GetHashCode()). Вы делаете это, наследуя свой интерфейс от IEquatable().

Ответ 3

I konw, это старый вопрос, но все представленные примеры показывают, как сравнивать два экземпляра класса, и никто не указывает, как сравнивать два экземпляра интерфейса.

В некоторых случаях это самый DRY-способ сравнения интерфейсов.

public interface IHaveAProblem
{
    string Issue { get; set; }
}

public class IHaveAProblemComparer : IComparer<IHaveAProblem>, IEqualityComparer<IHaveAProblem>
{
    public int Compare(IHaveAProblem x, IHaveAProblem y)
    {
        return string.Compare(x.Issue, y.Issue);
    }

    public bool Equals(IHaveAProblem x, IHaveAProblem y)
    {
        return string.Equals(x.Issue, y.Issue);
    }

    public int GetHashCode(IHaveAProblem obj)
    {
        return obj.GetHashCode();
    }
}

Использование

IHaveAProblemComparer comparer = new IHaveAProblemComparer();

List<IHaveAProblem> myListOfInterfaces = GetSomeIHaveAProblemObjects();
myListOfInterfaces.Sort(comparer); // items ordered by Issue

IHaveAProblem obj1 = new SomeProblemTypeA() { Issue = "Example1" };
IHaveAProblem obj2 = new SomeProblemTypeB() { Issue = "Example2" };

bool areEquals = comparer.Equals(obj1, obj2); // False

Ответ 4

В С# операторы статичны и переопределяют статические методы... messy.

Почему бы вам просто не переопределить метод Equals(), который унаследован от объекта? Это довольно просто, и вам не пришлось бы вмешиваться в переопределение статических методов.

Ответ 5

Вы пытались реализовать IComparable?

Вот так:

public interface IHaveAProblem : IComparable
{
    string Issue { get; set; }
}

И затем в реализации класса:

public class SomeProblem : IHaveAProblem
{
    public string Issue { get; set; }

    ...

    public int CompareTo(object obj)
    {
        return Issue.CompareTo(((SomeProblem)obj).Issue);
    }
}

Обратите внимание, что это работает только при сравнении двух экземпляров SomeProblem, но не с любыми другими реализациями интерфейса IHaveAProblem.

Не уверен, что может возникнуть исключение NullReferenceException.