Luffy1
@Luffy1
Student, Junior .NET programmer, C#, JS, HTML/CSS

Провёл очень подробный эксперимент по Equals, ReferenceEquals и ==. Провёл наблюдения и сделал кое-какие выводы. Верны ли мои выводы?

Решил подробно изучить то, что именно сравнивают Equals, ReferenceEquals и == при сравнении разных объектов одинаковых и разных типов. Полазил тут и почитал моменты, которые меня интересовали, вроде, никакие лазейки не упустил:
https://docs.microsoft.com/ru-ru/dotnet/csharp/lan...
https://docs.microsoft.com/ru-ru/dotnet/api/system...
https://docs.microsoft.com/ru-ru/dotnet/api/system...
https://docs.microsoft.com/ru-ru/dotnet/api/system...
А вот сам эксперимент с выводами:
using System;
using System.Collections.Generic;
using System.Text;
using static System.Console;

namespace Workspace
{
  class Program
  {
    static void Main()
    {
      //Классы:
      A a = new A("Den");
      A a2 = new A("Den");
      WriteLine(a.Equals(a2)); //False
      WriteLine(ReferenceEquals(a, a2)); //False
      WriteLine(a == a2); //False
      WriteLine();

      A a3 = new A("Den");
      A a4 = new A("Yan");
      WriteLine(a3.Equals(a4)); //False
      WriteLine(ReferenceEquals(a3, a4)); //False
      WriteLine(a3 == a4); //False
      WriteLine();

      A a5 = new A("Den");
      object a6 = new A("Den");
      WriteLine(a5.Equals(a6)); //False
      WriteLine(ReferenceEquals(a5, a6)); //False
      WriteLine(a5 == a6); //False
      WriteLine();

      A a7 = new A("Den");
      object a8 = new A("Yan");
      WriteLine(a7.Equals(a8)); //False
      WriteLine(ReferenceEquals(a7, a8)); //False
      WriteLine(a7 == a8); //False
      WriteLine();

      ////////////////////////////////////////
      WriteLine();
      WriteLine();
      WriteLine();

      A b = new B("Den", 19);
      A b2 = new B("Den", 19);
      WriteLine(b.Equals(b2)); //False
      WriteLine(ReferenceEquals(b, b2)); //False
      WriteLine(b == b2); //False
      WriteLine();

      A b3 = new B("Den", 19);
      A b4 = new B("Yan", 19);
      WriteLine(b3.Equals(b4)); //False
      WriteLine(ReferenceEquals(b3, b4)); //False
      WriteLine(b3 == b4); //False
      WriteLine();

      A b5 = new B("Den", 19);
      object b6 = new B("Den", 19);
      WriteLine(b5.Equals(b6)); //False
      WriteLine(ReferenceEquals(b5, b6)); //False
      WriteLine(b5 == b6); //False
      WriteLine();

      A b7 = new B("Den", 19);
      object b8 = new B("Yan", 19);
      WriteLine(b7.Equals(b8)); //False
      WriteLine(ReferenceEquals(b7, b8)); //False
      WriteLine(b7 == b8); //False
      WriteLine();


      WriteLine();
      WriteLine();
      WriteLine();
      WriteLine();
      WriteLine();
      WriteLine();


      //Структуры:
      A2 a222 = new A2(2, 1, 3);
      A2 a22 = new A2(2, 1, 3);
      WriteLine(a222.Equals(a22)); //True
      WriteLine(ReferenceEquals(a222, a22)); //False
                                             //WriteLine(a222 == a22); оператор == невозможно применить к структуре
      WriteLine();

      A2 a23 = new A2(2, 1, 3);
      A2 a24 = new A2(2, 4, 3);
      WriteLine(a23.Equals(a24)); //False
      WriteLine(ReferenceEquals(a23, a24)); //False
      WriteLine();

      A2 a25 = new A2(2, 1, 3);
      object a26 = new A2(2, 1, 3);
      WriteLine(a25.Equals(a26)); //True
      WriteLine(ReferenceEquals(a25, a26)); //False
      WriteLine();

      A2 a27 = new A2(2, 1, 3);
      object a28 = new A2(2, 4, 3);
      WriteLine(a27.Equals(a28)); //False
      WriteLine(ReferenceEquals(a27, a28)); //False
      WriteLine();

      ////////////////////////////////////////
      WriteLine();
      WriteLine();
      WriteLine();

      A2 a22222 = new A2(2, 1, 3);
      B2 a2222 = new B2(2, 1, 3);
      WriteLine(a22222.Equals(a2222)); //False
      WriteLine(ReferenceEquals(a22222, a2222)); //False
      WriteLine();

      A2 a223 = new A2(2, 1, 3);
      B2 a224 = new B2(2, 4, 3);
      WriteLine(a223.Equals(a224)); //False
      WriteLine(ReferenceEquals(a223, a224)); //False
      WriteLine();

      A2 a225 = new A2(2, 1, 3);
      object a226 = new B2(2, 1, 3);
      WriteLine(a225.Equals(a226)); //False
      WriteLine(ReferenceEquals(a225, a226)); //False
      WriteLine();

      A2 a227 = new A2(2, 1, 3);
      object a228 = new B2(2, 4, 3);
      WriteLine(a227.Equals(a228)); //False
      WriteLine(ReferenceEquals(a227, a228)); //False
      WriteLine();

      object a229 = new A2(2, 1, 3);
      object a220 = new B2(2, 1, 3);
      WriteLine(a229.Equals(a220)); //False
      WriteLine(ReferenceEquals(a229, a220)); //False
      WriteLine();


      WriteLine();
      WriteLine();
      WriteLine();
      WriteLine();
      WriteLine();
      WriteLine();


      //Массивы:
      int[] c = new int[5];
      int[] c2 = new int[5];

      WriteLine(c.Equals(c2)); //False
      WriteLine(ReferenceEquals(c, c2)); //False
      WriteLine(c == c2); //False
      WriteLine();

      long[] c3 = new long[5];
      int[] c4 = new int[5];
      WriteLine(c3.Equals(c4)); //False
      WriteLine(ReferenceEquals(c3, c4)); //False
      /*WriteLine(c3 == c4);*/ //Из-за разности типов (long[] и int[]) - невозможно применить
      WriteLine();

      for (int i = 0; i < c.Length; i++)
      {
        c[i] = i;
        c2[i] = i;
        c3[i] = i;
        c4[i] = i;
      }

      WriteLine(c.Equals(c2)); //False
      WriteLine(ReferenceEquals(c, c2)); //False
      WriteLine(c == c2); //False
      WriteLine();

      WriteLine(c3.Equals(c4)); //False
      WriteLine(ReferenceEquals(c3, c4)); //False
      WriteLine();

      c2[2] = 45;
      c4[2] = 55;

      WriteLine(c.Equals(c2)); //False
      WriteLine(ReferenceEquals(c, c2)); //False
      WriteLine(c == c2); //False
      WriteLine();

      WriteLine(c3.Equals(c4)); //False
      WriteLine(ReferenceEquals(c3, c4)); //False
      WriteLine();


      WriteLine();
      WriteLine();
      WriteLine();
      WriteLine();
      WriteLine();
      WriteLine();


      //String:
      string d = "8";
      string d2 = "8";
      WriteLine(d.Equals(d2)); //True
      WriteLine(ReferenceEquals(d, d2)); //True
      WriteLine(d == d2); //True
      WriteLine();

      string d3 = "8";
      object d4 = "8";
      WriteLine(d3.Equals(d4)); //True
      WriteLine(ReferenceEquals(d3, d4)); //True
      WriteLine(d3 == d4); //True
      WriteLine();

      string d5 = new string("8");
      string d6 = new string("8");
      WriteLine(d5.Equals(d6)); //True
      WriteLine(ReferenceEquals(d5, d6)); //False
      WriteLine(d5 == d6); //True
      WriteLine();

      string d7 = new string("8");
      object d8 = new string("8");
      WriteLine(d7.Equals(d8)); //True
      WriteLine(ReferenceEquals(d7, d8)); //False
      WriteLine(d7 == d8); //False
      WriteLine();

      object d9 = new string("8");
      object d0 = new string("8");
      WriteLine(d9.Equals(d0)); //True
      WriteLine(ReferenceEquals(d9, d0)); //False
      WriteLine(d9 == d0); //False
      WriteLine();

      ////////////////////////////////////////
      WriteLine();
      WriteLine();
      WriteLine();

      string d01 = "8";
      string d02 = "9";
      WriteLine(d01.Equals(d02)); //False
      WriteLine(ReferenceEquals(d01, d02)); //False
      WriteLine(d01 == d02); //False
      WriteLine();

      string d03 = "8";
      object d04 = "9";
      WriteLine(d03.Equals(d04)); //False
      WriteLine(ReferenceEquals(d03, d04)); //False
      WriteLine(d03 == d04); //False
      WriteLine();

      string d05 = new string("8");
      string d06 = new string("9");
      WriteLine(d05.Equals(d06)); //False
      WriteLine(ReferenceEquals(d05, d06)); //False
      WriteLine(d05 == d06); //False
      WriteLine();

      string d07 = new string("8");
      object d08 = new string("9");
      WriteLine(d07.Equals(d08)); //False
      WriteLine(ReferenceEquals(d07, d08)); //False
      WriteLine(d07 == d08); //False
      WriteLine();

      object h = "8";
      object hh = "8";
      WriteLine(h.Equals(hh)); //True
      WriteLine(ReferenceEquals(h, hh)); //True
      WriteLine(h == hh); //True
      WriteLine();





      //Другие примитивные типы:
      int g = 5;
      int g2 = 5;
      WriteLine(g.Equals(g2)); //True
      WriteLine(ReferenceEquals(g, g2)); //False
      WriteLine(g == g2); //True
      WriteLine();

      int g3 = 5;
      long g4 = 5;
      WriteLine(g3.Equals(g4)); //False
      WriteLine(ReferenceEquals(g3, g4)); //False
      WriteLine(g3 == g4); //True
      WriteLine();

      int g5 = 5;
      object g6 = 5;
      WriteLine(g5.Equals(g6)); //True
      WriteLine(ReferenceEquals(g5, g6)); //False
                                          //WriteLine(g5 == g6); //Из-за разности типов (int и object) - невозможно применить
      WriteLine();

      object g7 = 5;
      object g8 = 5;
      WriteLine(g7.Equals(g8)); //True
      WriteLine(ReferenceEquals(g7, g8)); //False
      WriteLine(g7 == g8); //False
      WriteLine();


      //ReferenceEquals --- нельзя переопределить!


      //Вывод:

        //Если не переопределять:

          //Классы:

            //Equals: проверяет равенство ссылок
            //ReferenceEquals: проверяет равенство ссылок
            //==: проверяет равенство ссылок

          //Структуры:

            //Equals: сравнивает названия(типы) структур и значения соответственных полей\свойств
            //ReferenceEquals: проверяет равенство ссылок
            //==: не применяется(возможно, можно переопределить, но не проверял это)

          //Массивы:

            //Equals: проверяет равенство ссылок, несмотря на значения ячеек и возможное равенство соответственных ячеек
            //ReferenceEquals: проверяет равенство ссылок
            //==: проверяет равенство ссылок, но если разные типы массивов, то применить нельзя
  • Вопрос задан
  • 90 просмотров
Решения вопроса 1
yarosroman
@yarosroman Куратор тега C#
C# the best
Рано тебе еще такие эксперименты проводить, не зная платформы и ее внутренностей и выводы.
Ссылочные сравниваются тупо по ссылке, если не переопределено иное.
1. Мне интересно, когда ты сравнивал два int через ReferenceEquals (а я сразу скажу, будет False), примерно представлял, что происходит и почему даже на одной переменной всегда будет False? И какие ссылки сравниваются? Указатели на значение в стеке? НЕТ!!!!!! Происходит упаковка и сравниваются два разных объекта, даже на одной переменной.

2. что int и далее значимые типы не от object наследуются, а от System.ValueType. У ValueType переопределен Equals. Так и что он делает: сравнивает типы, так как мы передаем object (и опять здравствуй упаковка родная), проверяет возможность побитового сравнения, что относится к примитивным типам и если оно невозможно, для каждого поля (в том числе и приватных) вызывает Equals, причем через рефлексию!!!!!!!!!!! А там если есть значимые поля без переопределенного Equals, здравствуй упаковка.

3. Сравнивать int и long через Equals еще тот изврат, да у примитивных типов есть перегрузки Equals, типа
public bool Equals(int obj)
{
	return this == obj;
}

те у int перегрузка с int, long c long и тд. если сравнивая через == у тебя сначала приведение типов срабатывает и потом сравнение, а при Equals, так как нет перегрузки необходимой вызывается ValueType(object), срабатывает сначала, она родненькая, упаковка, а потом сравнение типов и False;

4. Про сравнение структур через ReferenceEquals уже писал.

А мне интересно, вот теперь какие выводы ты для себя сделал? Просто эксперимент и все?
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
firedragon
@firedragon
Не джун-мидл-сеньор, а трус-балбес-бывалый.
классы сравниваются по хэшу.
хотя вы можете смухлевать и переопределить хэш
или эквал что в некоторых моментах бывает важно
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы