C # Переопределяющий оператор == когда класс наследуется от интерфейса.Могу ли я использовать == с интерфейсом или как это предотвратить? - PullRequest
0 голосов
/ 28 сентября 2019

Я унаследовал некоторый код, в котором Equals был переопределен, но не ==.Я исправил это, но заметил больше проблем.В вызывающем коде объекты строятся с использованием интерфейсов, а затем сравниваются, и результаты не соответствуют ожиданиям.Я поставил полный минимальный пример ниже.Вкратце, учитывая, что ISilly i1 = new Silly () и ISilly i2 = new Silly, i1 == i2 возвращают false, не соответствует действительности.Есть ли способ исправить это, и я должен?Я видел несколько аргументов в духе «взаимодействия i1 и i2. Может быть много классов, производных от ISilly, поэтому спрашиваю, не имеет ли смысл i1 и i2, кроме как в смысле равенства ссылок».Если это ответ, то у меня будут два вопроса:

  1. Почему Equals так красиво работает?
  2. Как мне остановить программиста приложения от вызова "i1 == i2"?Для него / нее более естественно написать это, чем i1.Equals (i2).

Я пытался выставить общедоступный статический оператор bool == (ISilly s1, ISilly s2) - обратите внимание на интерфейс вместоимя классаЯ получаю ошибку компилятора.

Что мне здесь не хватает?Я попытался найти статью, которая касается этого, но безуспешно.Я бы подумал, что это общая проблема.

Пожалуйста, дайте мне знать, если что-то неясно, или я могу предоставить больше информации.Спасибо, Дэйв

ОБНОВЛЕНИЕ !!! Я только что нашел этот связанный вопрос: Перегрузка операторов с помощью интерфейса на основе программирования в C # Пока я читаю, ответ кажетсязаявите, что вы просто не можете использовать == с интерфейсами, и один из ответов предлагает использовать сторонний инструмент, такой как Resharper, чтобы запретить его.Учитывая, какие неприятные ошибки он может вызвать, я вообще ставлю под сомнение полезность ==.Зачем вообще это позволять?

namespace EqualityProblems
{
    class Program
    {
        static void Main(string[] args)
        {
            // just use class, not interface!
            Silly s1 = new Silly();
            Silly s2 = new Silly();
            Silly s3 = new Silly(42);
            Silly s4 = null;
            Silly s5 = null;

            Console.WriteLine("s1.Equals(s2) should be true " + s1.Equals(s2)); // should be true
            Console.WriteLine("s1.Equals(s3) should be false " + s1.Equals(s3)); // should be false
            Console.WriteLine("s1.Equals(s4) should be false " + s1.Equals(s4)); // should be false
            Console.WriteLine("s1 == s2 should be true " + (s1 == s2)); // should be true
            Console.WriteLine("s1 != s2 should be false " + (s1 != s2)); // should be false
            Console.WriteLine("s1 == s3 should be false " + (s1 == s3)); // should be false
            Console.WriteLine("s4 == s1 should be false " + (s4 == s1)); // should be false
            Console.WriteLine("s1 == s4 should be false " + (s1 == s4)); // should be false
            Console.WriteLine("s4 == s5 should be true " + (s4 == s5)); // should be true;both are null

            //Console.WriteLine("s4.Equals(s1) should crash " + s4.Equals(s1)); // should crash. s4 is null

            ISilly i1 = new Silly();
            ISilly i2 = new Silly();
            ISilly i3 = new Silly(42);
            ISilly i4 = null;
            ISilly i5 = null;

            Console.WriteLine("i1.Equals(i2) should be true " + i1.Equals(i2)); // should be true
            Console.WriteLine("i1.Equals(i3) should be false " + i1.Equals(i3)); // should be false
            Console.WriteLine("i1.Equals(i4) should be false " + i1.Equals(i4)); // should be false
            Console.WriteLine("i1 == i2 should be true " + (i1 == i2)); // should be true BUT IS FALSE
            Console.WriteLine("i1 != i2 should be false " + (i1 != i2)); // should be false BUT IS TRUE
            Console.WriteLine("i1 == i3 should be false " + (i1 == i3)); // should be false
            Console.WriteLine("i4 == i1 should be false " + (i4 == i1)); // should be false
            Console.WriteLine("i1 == i4 should be false " + (i1 == i4)); // should be false
            Console.WriteLine("i4 == i5 should be true " + (i4 == i5)); // should be true;both are null

            //Console.WriteLine("i4.Equals(i1) should crash " + i4.Equals(i1)); // should crash. i4 is null

        }
    }

    public interface ISilly
    {
        int Length { get; set; }
    }

    public class Silly : ISilly
    {
        public Silly(int n) { Length = n; }
        public Silly() { Length = 7; }
        public int Length { get; set; }
        public override bool Equals(object obj)
        {
            return obj is ISilly sl && (sl.Length == Length);
        }

        public bool Equals(Silly other)
        {
            if (other == null) return false;
            return Length == other.Length;
        }

        public override int GetHashCode()
        {
            return Length;
        }

        public static bool operator ==(Silly s1, Silly s2)
        {
            if (ReferenceEquals(s1, null))
            {
                return ReferenceEquals(s2, null) ? true : false;
            }
            return s1.Equals(s2);
        }

        public static bool operator !=(Silly fs1, Silly fs2)
        {
            return !fs1.Equals(fs2);
        }


    }
}

1 Ответ

0 голосов
/ 01 октября 2019

Не знаю, возможно ли это для вас, но если вы можете использовать абстрактный интерфейс вместо интерфейса, то вы могли бы реализовать оператор == как вызов абстрактного Equals ().

Таким образом, любой, использующий == в производном классе, получит тот же результат, что и вызов Equals.

...