Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.81/48: Рейтинг темы: голосов - 48, средняя оценка - 4.81
14 / 14 / 3
Регистрация: 07.01.2014
Сообщений: 37

Разница между == и Equals()

22.01.2014, 08:39. Показов 10444. Ответов 13
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
C#
1
2
3
4
5
6
7
8
const int age = 25;
            const short newAge = 25;
 
            Console.WriteLine(age == newAge);  //true
            Console.WriteLine(newAge.Equals(age)); //false
            Console.ReadLine();
 
            Console.ReadKey();
Почему в первом значении возвращает true, во втором false?

Если менять переменную newAge на int тогда true.

Может кто объяснить почему так?
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
22.01.2014, 08:39
Ответы с готовыми решениями:

Equals и == в чем разница?
Собственно реализовал в классе Equals и ==; Но потом подумал, а ведь это одно и то же. То зачем описывать полностью == Если можно...

Разница между j++ и ++j
Есть ли разница между for ( j=0; j < n; j++) и ( j=0; j < n; ++j) Видел , что так и так пишут. Сам же только по 1му способу

разница между C# и C++
Здравствуйте! Может ли кто-нибудь досказать по пунктам разницу между C++ и C# их приоритеты

13
 Аватар для Дмитрий3241
660 / 530 / 137
Регистрация: 07.07.2011
Сообщений: 1,232
Записей в блоге: 6
22.01.2014, 08:47
Цитата Сообщение от ПрограммерООП Посмотреть сообщение
Может кто объяснить почему так?
Сразу скажу что не знаю всех тонкостей, но мне кажется, что оператор == делает приведение типов и сравнивает значения уже у приведенных, а Equals сразу же видит, что типы разные и выдает false...
P.S: Все что я написал выше просто предположение.

Добавлено через 3 минуты
На msdn говорят что Equals нужно писать вот так:
C#
1
2
3
4
5
   public override bool Equals(Object obj) 
{
      if (obj == null || GetType() != obj.GetType()) return false;
      ...
}
2
Администратор
Эксперт .NET
 Аватар для tezaurismosis
9674 / 4826 / 763
Регистрация: 17.04.2012
Сообщений: 9,664
Записей в блоге: 14
22.01.2014, 10:07
Вот вам небольшой листинг для размышления, я разбирался с этой темой и писал вот этот код. Комментарии прилагаются.
Кликните здесь для просмотра всего текста
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace ConsoleAppTest
{
    /// <summary>
    /// Пример реализации равенства: переопределение Object.Equals(Object) 
    /// и реализация обобщённого интерфейса IEquatable.
    /// Реализация собственного метода GetHashCode().
    /// 
    /// Взято из книги Бена Ватсона "C# 4.0 на примерах"
    /// </summary>
    public struct Vertex3d : IEquatable<Vertex3d>
    {
        public double _x;
        public double _y;
        public double _z;
 
        public Vertex3d(double x, double y, double z) {
            this._x = x;
            this._y = y;
            this._z = z;
        }
 
        public override bool Equals(object obj) {
            // Сравнение с null всегда возвращает false
            if (obj == null)
                return false;
            // Если сравниваемые объекты имеют разный тип, равенство не верно
            if (obj.GetType() != this.GetType())
                return false;
            // Вызываем специфический метод сравнения
            return Equals((Vertex3d)obj);
        }
 
        // Реализация интерфейса IEquatable<T>
        public bool Equals(Vertex3d other) {
            // Сравниваем поля по-одному
            return this._x == other._x
                && this._y == other._y
                && this._z == other._z;
        }
 
        public override int GetHashCode() {
            return (((int)_x ^ (int)_y) << 16) |
                (((int)_y ^ (int)_z) & 0x0000FFFF);
        }
    }
 
    /// <summary>
    /// Пример реализации равенства: переопределение Object.Equals(Object) 
    /// Реализация метода GetHashCode() на основе хэш-кода строки-представления.
    /// 
    /// Взято из книги Эндрю Троэлсена "Язык программирования C# 2010 и платформа .NET 4"
    /// </summary>
    public class Person
    {
        public string FirstName { set; get; }
        public string LastName { set; get; }
        public int Age { set; get; }
 
        // Переопределение этого метода в данном пример необходимо для
        // реализации метода GetHashCode()
        public override string ToString() {
            return String.Format("First Name: {0}, Last Name: {1}, Age: {2}",
                FirstName, LastName, Age);
        }
 
        /* Примечание из MSDN по поводу применения оператора is:
         * Метод Equals использует метод GetType, чтобы определить, совпадают ли типы 
         * времени выполнения для двух объектов. (Обратите внимание, что typeof в данном 
         * случае не используется, так как он возвращает статический тип.) Если бы этот метод 
         * использовал проверку формы obj is Point, эта проверка возвращала бы значение true, 
         * если бы параметр obj являлся экземпляром класса, производного от данного, даже несмотря 
         * на принадлежность параметра obj и текущего экземпляра к различным типам среды выполнения. 
         */
        public override bool Equals(object obj) {
            if (obj is Person && obj != null) {
                Person temp = (Person)obj;
                // Сравнение на основе равенства свойств (properties)
                if (temp.FirstName == this.FirstName
                    && temp.LastName == this.LastName
                    && temp.Age == this.Age)
                    return true;
                return false;
            }
            return false;
        }
 
        // Получение хэш-кода на основе хэш-кода строки-представления
        public override int GetHashCode() {
            return this.ToString().GetHashCode();
        }
    }
 
    /// <summary>
    /// Пример реализации равенства: переопределение Object.Equals(Object) 
    /// и реализация обобщённого интерфейса IEquatable.
    /// Реализация собственного метода GetHashCode().
    /// Данная структура описывает прямоугольную область, что предполагает 
    /// равенство областей 10х5 и 5х10. Здесь это учтено.
    /// 
    /// Взято из книги братьев Албахари "C# 5.0 in a Nutshell"
    /// </summary>
    public struct Area : IEquatable<Area>
    {
        public readonly int Measure1;
        public readonly int Measure2;
 
        public Area(int m1, int m2) {
            Measure1 = Math.Min(m1, m2);
            Measure2 = Math.Max(m1, m2);
        }
 
        // Переопределение Object.Equals(Object)
        // Если не использовать обнуляемые (nullable) типы, проверка 
        // obj != null не нужна. В обратном случае авторы предлагают 
        // следующее решение: 
        // Area? otherArea = other as Area?;
        // return otherArea.HasValue && Equals(otherArea.Value);
        public override bool Equals(object obj) {
            if (!(obj is Area)) return false;
            return Equals((Area)obj);
        }
 
        // Реализация IEquatable<T>
        public bool Equals(Area other) {
            return Measure1 == other.Measure1
                && Measure2 == other.Measure2;
        }
 
        /* Авторы предлагают для вычисления хэш-кода умножать
        одно из полей на простое число и складывать с другим полем.
        В случае, если в типе несколько полей, предлагается следующее:
        int hash = 17;
        hash = hash * 31 + field1.GetHashCode();
        hash = hash * 31 + field2.GetHashCode();
        hash = hash * 31 + field3.GetHashCode();
        ...
        return hash;
        (Числа 17 и 31 - простые)
        */
        public override int GetHashCode() {
            return Measure2 * 31 + Measure1;  // 31 - простое число
        }
 
        public static bool operator ==(Area a1, Area a2) {
            return a1.Equals(a2);
        }
 
        public static bool operator !=(Area a1, Area a2) {
            return !a1.Equals(a2);
        }
    }
 
    /// <summary>
    /// К примеру "подключаемого компаратора" (pluggable comparator)
    /// </summary>
    public class Customer
    {
        public string LastName;
        public string FirstName;
 
        public Customer(string first, string last) {
            LastName = last;
            FirstName = first;
        }
    }
 
    /// <summary>
    /// Пример использования подключаемого компаратора (pluggable comparator). 
    /// В классе Customer не переопределны методы установки равенства, поэтому 
    /// используются стандартные. Для придания особого смысла сравнению объектов 
    /// в словаре или хэш-таблице, мы можем использовать интерфейс IEqualityComparer
    /// или наследвать класс от абстрактного класса EqualityComparer.
    /// 
    /// Взято из книги братьев Албахари "C# 5.0 in a Nutshell"
    /// </summary>
    public class LastFirstEqComparer : EqualityComparer<Customer>
    {
        public override bool Equals(Customer x, Customer y) {
            return x.LastName == y.LastName
                && x.FirstName == y.FirstName;
        }
 
        public override int GetHashCode(Customer obj) {
            return (obj.FirstName + ";" + obj.LastName).GetHashCode();
        }
    }
 
    class Program
    {
        static void Main(string[] args) {
            #region Test for Vertex3d
            /* 
            Vertex3d v1 = new Vertex3d(10.0, 20.5, 3.2);
            Vertex3d v2 = new Vertex3d(5.1, -6.2, 0.0);
            Vertex3d v3 = new Vertex3d(10.0, 20.5, 3.2);
            Console.WriteLine(v1.Equals(v2));
            Console.WriteLine(v1.Equals(v3));
            Console.WriteLine(v1.Equals((object)v2));
            Console.WriteLine(v1.Equals((object)v3));
            Console.WriteLine("{0:x}", v1.GetHashCode());
 
            // Тест метода хэширования
            for (int i = 523; i < 528; i++)
                for (int j = 76; j < 81; j++)
                    for (int k = -1131; k < -1126; k++)
                        Console.WriteLine("{0:x}", new Vertex3d((int)i, (int)j, (int)k).GetHashCode());
            */
            #endregion
            #region Test for Person
            /* 
            Person gates = new Person
            {
                FirstName = "Bill",
                LastName = "Gates",
                Age = 50
            };
 
            Person jobs = new Person
            {
                FirstName = "Steve",
                LastName = "Jobs",
                Age = 53
            };
 
            Person knuth = new Person
            {
                FirstName = "Donald",
                LastName = "Knuth",
                Age = 60
            };
 
            Console.WriteLine(gates.Equals(knuth));
            Console.WriteLine("{0:x}", gates.GetHashCode());
            Console.WriteLine("{0:x}", jobs.GetHashCode());
            Console.WriteLine("{0:x}", knuth.GetHashCode());
            */
            #endregion
            #region Test for LastFirstEqComparer
            Customer c1 = new Customer("Bruce", "Wayne");
            Customer c2 = new Customer("Bruce", "Wayne");
            // В обоих случаях вывод - False, т.к. мы не переопределили
            // в классе Customer метод Equals и оператор ==, поэтому используется
            // сравнение по умолчанию
            Console.WriteLine(c1 == c2);
            Console.WriteLine(c1.Equals(c2));
            var eqComparer = new LastFirstEqComparer();
            var dict = new Dictionary<Customer, String>(eqComparer);
            dict[c1] = "Wayne";
            // Вывод - True, т.к. для сравнения используется специальный компаратор
            Console.WriteLine(dict.ContainsKey(c2));
            // Здесь воспользуемся стандартным компаратором
            var dictDefault = new Dictionary<Customer, String>(EqualityComparer<Customer>.Default);
            dictDefault[c1] = "Wayne";
            // Вывод - False
            Console.WriteLine(dictDefault.ContainsKey(c2));
            #endregion
        }
    }
}

Чтобы хорошо разобраться в теме, рекомендую прочитать главу об этом в книге Джеффри Рихтера "CLR via C#"
4
14 / 14 / 3
Регистрация: 07.01.2014
Сообщений: 37
22.01.2014, 10:45  [ТС]
Оказывается метод Equal не был предназначен для типа short
Написал следующий код, возвращает true
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public override bool Equals(object obj)
        {
            return obj is short && this == obj;
        }
 
        static void Main()
        {
            int age = 25;
            short newAge = 25;
 
            Console.WriteLine(age == newAge); 
            Console.WriteLine(newAge.Equals((object)(short)age)); 
            Console.ReadLine();
            
            Console.ReadKey();
        }
Так же помогла данная статья
0
11 / 10 / 8
Регистрация: 06.07.2015
Сообщений: 75
30.03.2017, 19:57
Тема древняя!!!
Но меня вот что заинтересовало. Почему код так работает?
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
static void Main()
    {
        const int age = 25;
        const short newAge = 25;
        Console.WriteLine(age == newAge);  //true
        Console.WriteLine(newAge.Equals(age)); //true
    
        Console.WriteLine();
 
        int p1 = 10;
        short p2 = 10;
        Console.WriteLine(p1 == p2);  //true
        Console.WriteLine(p2.Equals(p1)); //false
    }
Почему в первом случае true, а во втором false? Разные методы вызываются. А почему они разные вызываются?

PS. И почему у автора темы в первом случае false сработало?
0
 Аватар для Tsin
1180 / 488 / 188
Регистрация: 30.12.2012
Сообщений: 1,278
Записей в блоге: 2
30.03.2017, 20:39
Цитата Сообщение от Silvestor Посмотреть сообщение
Почему в первом случае true, а во втором false?
Я думаю, что это связано с CLR и особенностями компилятора. Константы определяются еще на этапе компиляции, и их значения жестко "зашиваются" в код. Компилятор видит, что значения одинаковые, а значит вполне вероятно, что и размещены они будут в одном и том же месте.

Во втором случае очевидно, что false, т.к. p1 и p2 - valuetypes.

Пусть меня поправят более опытные коллеги, потому что я не до конца уверен в своей правоте..
1
 Аватар для IamRain
4694 / 2702 / 734
Регистрация: 02.08.2011
Сообщений: 7,233
30.03.2017, 21:00
Дело не с особенностями компилятора, а в том, как Int16 реализует Equals method:
C referencesource.microsoft.com:
C#
1
2
3
4
5
6
7
8
9
10
11
12
public override bool Equals(Object obj) {
            if (!(obj is Int16)) {
                return false;
            }
            return m_value == ((Int16)obj).m_value;
        }
 
[System.Runtime.Versioning.NonVersionable]
        public bool Equals(Int16 obj)
        {
            return m_value == obj;
        }
При передаче Int32 типа отрабатывает первая перегрузка, которая проверяет тип параметра.
Соответственно при передаче Int16 просто сравниваются значения.
Получается, если во втором случае скастить Int32 к Int16, то получим ожидаемый результат:
Console.WriteLine(p2.Equals((short)p1)); //true
1
11 / 10 / 8
Регистрация: 06.07.2015
Сообщений: 75
30.03.2017, 21:20
Да , но почему в первом случае вызывается метод:
public bool Equals(Int16 obj)

Ведь по идее должен вызываться:
public override bool Equals(Object obj)
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
30.03.2017, 21:22
Цитата Сообщение от Silvestor Посмотреть сообщение
Да , но почему в первом случае вызывается метод:
public bool Equals(Int16 obj)
В первом случае вызывается Equals(Int32).
Вызывается он потому, что short неявно преобразуется в int, а перегрузка с int является лучшим кандидатом, чем перегрузка с object.
0
11 / 10 / 8
Регистрация: 06.07.2015
Сообщений: 75
30.03.2017, 21:38
Ничего подобного. Декомпилятор показывает вызов метода:

instance bool [mscorlib]System.Int16::Equals(int16)
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
30.03.2017, 22:20
Цитата Сообщение от Silvestor Посмотреть сообщение
Ничего подобного.
Ай, точно — я переменные местами перепутал.

Age — константа, к тому же ее значение входит в диапазон short. В этом случае int неявно преобразуется в short.
2
 Аватар для IamRain
4694 / 2702 / 734
Регистрация: 02.08.2011
Сообщений: 7,233
30.03.2017, 22:37
Silvestor, таки заставили в IL лезти,
Вот такой C# код:
C#
1
2
3
const int age = 25;
const short newAge = 25;            
Console.WriteLine(newAge.Equals(age)); //true
имеет вот такой IL: (распишу команды)
C#
1
2
3
4
5
6
7
8
9
10
.maxstack  2
  .locals init ([0] int16 V_0)
  IL_0000:  nop
  IL_0001:  ldc.i4.s   25  // Push num onto the stack as int32, short form  <-- Как Int32
  IL_0003:  stloc.0  // вытащить последнюю переменную из стека и положить в локальную переменную c индексом 0
  IL_0004:  ldloca.s   V_0  // вычислить адрес переменной по индексу 0.  
                            // Ятп - подразумевается положить значение по вычисленному адресу в регистр
  IL_0006:  ldc.i4.s   25  // Push num onto the stack as int32, short form  <-- Как Int32
  IL_0008:  call       instance bool [mscorlib]System.Int16::Equals(int16)
  IL_000d:  call       void [mscorlib]System.Console::WriteLine(bool)
Обратите внимание, независимо от типов констант, в стек были положены 32-битные значения.
То есть ятп С# компилятор преобразует целочисленные константы всегда в Int32. Рихтер также писал, что компилятор при арифметических операциях всегда оперирует 32-битными значениями.
Несмотря на то, что IL показывает вызов System.System.Int16::Equals(int16), по факту данные содержат 32-х битные значения (в этом мы только что убедились). А в рантайме Jitter доделывает всю работу.
Tsin, получается, вы были правы.

Добавлено через 7 минут
Хотя не, намудрил, ненужную работу сделал, , В первом случае int преобразуется в short, и срабатывает перегрузка c short параметром, во втором - уже с object параметром.
2
11 / 10 / 8
Регистрация: 06.07.2015
Сообщений: 75
30.03.2017, 22:51
Господа, тогда правильно ли я понимаю, что выбор выполняемого метода происходит на стадии компиляции в зависимости от типа константы!!? и от значений помещенных в них?
То есть, от типа константы newAge выбирается, что метод Equals будет вызываться для типа int16. Далее от типа и значения константы age выбирается версия перегруженного метода. И если бы в типе int16 была версия Equals с параметром int32, то вызвалась бы именно она. Но... так как представлены только версии с параметрами int16 и object, то компилятор решает вызывать версию с параметром int16 если значение константы менее 65000(2^16), и версию с параметром object если значение константы больше 65000, так как будет потеря данных. Правильны ли мои суждения?
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
30.03.2017, 23:08
Цитата Сообщение от Silvestor Посмотреть сообщение
правильно ли я понимаю, что выбор выполняемого метода происходит на стадии компиляции в зависимости от типа константы!!?
Разумеется. Перегрузка метода определяется на стадии компиляции.

Цитата Сообщение от Silvestor Посмотреть сообщение
так как представлены только версии с параметрами int16 и object, то компилятор решает вызывать версию с параметром int16 если значение константы менее 65000(2^16), и версию с параметром object если значение константы больше 65000, так как будет потеря данных. Правильны ли мои суждения?
Так точно.
Разве что компилятор не думает о потерях данных, а выбирает перегрузку по принципу "преобразуется ли аргумент неявно к типу параметра метода и какое из преобразований более специализировано".
Значения константы int, которые попадают в диапазон short, неявно преобразуются в этот тип, потому перегрузка с short и получается лучшим кандидатом.
3
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
30.03.2017, 23:08
Помогаю со студенческими работами здесь

Разница между С# и С++
Привет всем, до этого времени я как то программировал как любитель на С, и С++ ну и пробовал и другие языки. Но мне показалось что ...

Разница между VB .NET и С#
Многие говорят, что VB и С# одно и тоже. Я особо Visual Basic не знаю, но мне ка житься что это разные вешье . Может вы мне объясните...

Разница между this и base
Воззник такой вопрос: в чём разница между оператором base и this. Работает и base.Close() и this.Close() В чём интересно разница?

Разница между числами
Здравствуйте! Есть два числа : int xe = 10; int xu = 17; Как узнать больше ли xu чем xe на 5 ? То есть написать примерно след.: ...

Разница между 2 датами
Надо в консольке посчитать разницу между первой и второй датой... Вот что накопал пока что... Только не правильно... ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
14
Ответ Создать тему
Новые блоги и статьи
Программный контроль заполнения реквизита табличной части документа
Maks 02.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: реализовать контроль заполнения реквизита "ПричинаСписания". . .
wmic не является внутренней или внешней командой
Maks 02.04.2026
Решение: DISM / Online / Add-Capability / CapabilityName:WMIC~~~~ Отсюда: https:/ / winitpro. ru/ index. php/ 2025/ 02/ 14/ komanda-wmic-ne-naydena/
Программная установка даты и запрет ее изменения
Maks 02.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: при создании документов установить период списания автоматически. . .
Вывод данных в справочнике через динамический список
Maks 01.04.2026
Реализация из решения ниже выполнена на примере нетипового справочника "Спецтехника" разработанного в конфигурации КА2. Задача: вывести данные из ТЧ нетипового документа. . .
Программное заполнения текстового поля в реквизите формы документа
Maks 01.04.2026
Алгоритм из решения ниже реализован на нетиповом документе "ВыдачаОборудованияНаСпецтехнику" разработанного в конфигурации КА2, в дополнении к предыдущему решению. На форме документа создается. . .
К слову об оптимизации
kumehtar 01.04.2026
Вспоминаю начало 2000-х, университет, когда я писал на Delphi. Тогда среди программистов на форумах активно обсуждали аккуратную работу с памятью: нужно было следить за переменными, вовремя. . .
Идея фильтра интернета (сервер = слой+фильтр).
Hrethgir 31.03.2026
Суть идеи заключается в том, чтобы запустить свой сервер, о чём я если честно мечтал давно и давно приобрёл книгу как это сделать. Но не было причин его запускать. Очумелые учёные напечатали на. . .
Модель здравосоХранения 6. ESG-повестка и устойчивое развитие; углублённый анализ кадрового бренда
anaschu 31.03.2026
В прикрепленном документе раздумья о том, как можно поменять модель в будущем
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru