D
D
Denis Bredun2021-08-11 21:01:00
C++ / C#
Denis Bredun, 2021-08-11 21:01:00

Did a very detailed experiment on Equals, ReferenceEquals and ==. Conducted observations and made some conclusions. Are my conclusions correct?

I decided to study in detail what exactly Equals, ReferenceEquals and == compare when comparing different objects of the same and different types. I climbed here and read the moments that interested me, it seems that I did not miss any loopholes:
https://docs.microsoft.com/ru-ru/dotnet/csharp/lan...
https://docs.microsoft.com/ru -en/dotnet/api/system...
https://docs.microsoft.com/en-us/dotnet/api/system...
https://docs.microsoft.com/en-us/dotnet/api /system...
And here is the experiment itself with the conclusions:

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: проверяет равенство ссылок
            //==: проверяет равенство ссылок, но если разные типы массивов, то применить нельзя

Answer the question

In order to leave comments, you need to log in

2 answer(s)
R
Roman, 2021-08-12
@Luffy1

It's too early for you to conduct such experiments without knowing the platform and its internals and conclusions.
References are compared stupidly by reference, unless otherwise redefined.
1. I'm wondering, when you compared two ints using ReferenceEquals (and I'll say right away, it will be False), roughly imagined what was happening and why even on one variable it would always be False? And which links are compared? Pointers to a value on the stack? NO!!!!!! Packing occurs and two different objects are compared, even on the same variable.
2. that int and further value types are not inherited from object, but from System.ValueType. ValueType has Equals overridden. So what does it do: it compares types, since we are passing an object (and hello again, native packaging), checks the possibility of bitwise comparison, which applies to primitive types, and if it is not possible, calls Equals for each field (including private ones), and through reflection !!!!!!!!!! And there, if there are significant fields without redefined Equals, hello packaging.
3. Comparing int and long through Equals is still a perversion, but primitive types have overloads of Equals, such as

public bool Equals(int obj)
{
  return this == obj;
}

those have int overload with int, long c long and so on. if comparing through ==, type casting first works for you and then comparison, and with Equals, since there is no overload necessary, ValueType (object) is called, it works first, it is kind, packing, and then type comparison and False;
4. I already wrote about comparison of structures through ReferenceEquals.
And I'm wondering, now what conclusions have you drawn for yourself? Just an experiment is all?

V
Vladimir Korotenko, 2021-08-11
@firedragon

classes are compared by hash.
although you can cheat and redefine the hash
or equal, which is important at some points

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question