Подтвердить что ты не робот

5 способов проверки равенства .net.. почему? и который использовать?

Во время обучения .net(по С#) я нашел 5 способов проверки равенства между объектами.

  • Метод ReferenceEquals().
  • Виртуальный метод Equals(). (System.Object)
  • Статический метод Equals().
  • Метод Equals из интерфейса IEquatable.
  • Оператор сравнения ==.

Мой вопрос:

  • Почему существует так много методов Equals() и оператор сравнения?
  • Какой из виртуальных Equals() или IEquatable Equals() можно использовать... (скажем, если мы используем наши собственные классы коллекции)
4b9b3361

Ответ 1

1 - Ссылка равна проверке, если две ссылочные типы переменных (классы, а не структуры) относятся к одному и тому же адресу памяти.

2 - Виртуальный метод Equals() проверяет, являются ли два объекта эквивалентными. Скажем, у вас есть этот класс:

class TestClass{
    public int Property1{get;set}
    public int Property2{get;set}

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

        var convertedObj = (TestClass)obj;

        return (convertedObj.Property1 == this.Property1 && convertedObj.Property2 == this.Property2);
    }
}

и вы создаете два объекта из этого класса:

var o1 = new TestClass{property1 = 1, property2 = 2}
var o2 = new TestClass{property1 = 1, property2 = 2}

хотя оба объекта не являются одним и тем же экземпляром TestClass, вызов o1.Equals(o2) вернет true.

3 - Статический метод Equals используется для обработки проблем, когда в проверке есть нулевое значение. Представьте себе это, например:

TestClass o1 = null;
var o2 = new TestClass{property1 = 1, property2 = 2}

Если вы попробуете это:

o1.Equals(o2);

вы получите исключение NullReferenceException, потому что o1 указывает на ничего. Чтобы решить эту проблему, выполните следующее:

Object.Equals(O1, O2);

Этот метод готов для обработки нулевых ссылок.

4. Интерфейс IEquatable предоставляется .Net, поэтому вам не нужно делать броски внутри вашего метода Equals. Если компилятор узнает о том, что вы реализовали интерфейс в классе для типа, который вы пытаетесь проверить на равенство, он даст этому приоритету метода над переопределением Object.Equals(Object). Например:

class TestClass : IEquatable<TestClass>
{
    public int Property1 { get; set; }
    public int Property2 { get; set; }

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

        var convertedObj = (TestClass)obj;

        return (convertedObj.Property1 == this.Property1 && convertedObj.Property2 == this.Property2);
    }

    #region IEquatable<TestClass> Members

    public bool Equals(TestClass other)
    {
        return (other.Property1 == this.Property1 && other.Property2 == this.Property2);
    }

    #endregion
}

теперь, если мы это сделаем:

var o1 = new TestClass{property1 = 1, property2 = 2}
var o2 = new TestClass{property1 = 1, property2 = 2}
o1.Equals(o2);

Вызываемый метод равен Equals (TestClass) до Equals (Object).

5 - Оператор == обычно означает то же, что и ReferenceEquals, он проверяет, указывают ли две переменные на один и тот же адрес памяти. Исход состоит в том, что этот оператор можно переопределить для выполнения других типов проверок. Например, в строках он проверяет, эквивалентны ли два разных экземпляра.

Это полезная ссылка для понимания равенств в .Net лучше:

Ответ 2

Метод ReferenceEquals().

Это используется, чтобы проверить, указывают ли две заданные переменные (символ ссылается) на один и тот же объект. Это буквально эквивалентно ((object)a) == ((object)b). Если вы переопределите оператор сравнения (==), то ReferenceEquals поддерживает способ доступа к по умолчанию.

Однако, если вы имеете дело со типом значения (например, struct), то этот всегда возвращает false. Это связано с тем, что сравнение каждого типа значений для нового объекта так естественно, что ссылки не будут равными.


Виртуальный метод Equals(). (System.Object)

Это метод по умолчанию для семантического сравнения двух объектов (любого типа). Каждый класс переопределяет это по своему усмотрению. По умолчанию это эквивалентно вызову CLR (InternalEquals), который в основном сравнивает ссылки на память.

Обратите внимание: если два объекта возвращают true для Equals(), то GetHashCode() для каждого из них должно быть равно. Однако, если хэш-коды для двух объектов эквивалентны значению (т.е. obj1.GetHashCode() == obj2.GetHashCode()), это не означает, что Equals() является истинным.

Ваш класс должен обычно реализовывать Equals и GetHashCode как средство для различения экземпляров класса и должен реализовывать этот или оператор == (идеально оба), если это тип значения.

Примечание. Для типов значений поведение Equals по умолчанию - это значение ValueType.Equals(), которое, если вы смотрите в Reflector (или читаете описание MSDN) использует отражение для сравнения членов двух экземпляров значения.


Статический метод Equals().

Это эквивалентно return ((objA == objB) || (((objA != null) && (objB != null)) && objA.Equals(objB))), где каждый тип преобразуется в Object для тестирования. Мое тестирование показывает, что перегруженные операторы сравнения игнорируются, но ваш метод Equals будет использоваться, если объекты не являются нулевыми и не являются той же ссылкой. Таким образом, a.Equals(b) не обязательно равно object.Equals(a, b) (для случаев, когда ((object)a) == ((object)b) или или b равно null).


Метод Equals из интерфейса IEquatable.

IEquatable предоставляет вам возможность специально изучить сравнение с экземплярами одного и того же класса. Сказав, что ваш метод Equals должен обрабатывать поведение таким же образом:

Если вы реализуете Equals, вы должны также переопределить базовый класс реализации Object.Equals(Object) и GetHashCode так что их поведение непротиворечиво с темой IEquatable.Equals Метод

Тем не менее вы должны реализовать IEquatable:

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


Оператор сравнения ==

Оператор сравнения по умолчанию возвращает true, когда оба объекта являются одной и той же ссылкой.

Это не рекомендуется, чтобы переопределить оператор сравнения, если вы не имеете дело со значением типа (в этом случае рекомендуется вместе с методом Equals) или неизменным ссылочным типом, который вы обычно сравниваете по значению (например, string). Всегда выполняйте != в одно и то же время (на самом деле я получаю ошибку requires a matching operator '!=' to also be defined, если я этого не делаю).


Ресурсы

Ответ 3

Каждая версия равенства несколько отличается.

ReferenceEquals тесты для ссылочного равенства.

virtual Equals по умолчанию проверяет ссылочное равенство для типов классов и равенство значений для типов struct. Его можно переопределить, если при желании определить равенство по-разному; и должны быть переопределены для типов значений.

static Equals просто вызывает virtual Equals, но также допускает аргументы null.

IEquatable<T>.Equals - общий эквивалент типа virtual Equals.

operator== предназначен как по умолчанию virtual Equals, что означает ссылочное равенство для типов классов (если класс также не переопределяет другие операторы). Он также должен быть переопределен для типов значений.

Если вы пишете свой собственный класс коллекции, используйте IEqualityComparer<T>, по умолчанию EqualityComparer<T>.Default. Не используйте сравнение сравнений напрямую.

Ответ 4

Для примитивов придерживайтесь оператора ==.

В большинстве объектов, поставляемых в платформе .NET, и любых настраиваемых объектов, которые вы создаете .Equals(), и оператор == проверяет, будут ли два объекта ссылаться на один и тот же объект в куче.

Цель интерфейса IEquatable - переопределить метод .Equals(), чтобы изменить его поведение, проверяя для ссылочного равенства, чтобы проверить равенство значений. Тип System.String является примером встроенного объекта .NET, который реализует этот интерфейс.

Метод .ReferenceEquals() предоставляет возможность разработчикам, которые переопределили стандартный метод .Equals(), чтобы все еще иметь возможность проверять два объекта для ссылочного равенства.