C # Разрешено ли перегружать == оператор сравнивать только некоторые свойства? [Дубликат]

Отличные ответы выше. Я хочу только добавить, что внутри области вашей функции вы можете присвоить значение этой переменной переменной let self = this;, а затем внутри обратного вызова просто обратиться к данным типа self.data.

Ваш код :

function MyConstructor(data, transport) {
    this.data = data;

    let self = this;   //ADD THIS LINE

    transport.on('data', function () {
        alert(self.data);   //USE IT LIKE THIS
    });
}

// Mock transport object
var transport = {
    on: function(event, callback) {
        setTimeout(callback, 1000);
    }
};

// called as
var obj = new MyConstructor('foo', transport);
445
задан poke 16 December 2015 в 10:27
поделиться

16 ответов

Когда выражение == используется для выражения типа object, оно будет разрешено System.Object.ReferenceEquals .

Equals является всего лишь методом virtual и ведет себя как таковой, поэтому будет использоваться переопределенная версия (которая для типа string сравнивает содержимое).

355
ответ дан poke 22 August 2018 в 14:16
поделиться
  • 1
    Если оператор специально не реализован в классе – Dominic Cronin 19 November 2011 в 23:11
  • 2
    @DominicCronin Это неправда. Даже если == реализован в классе, он будет проигнорирован, так как тип слева от сравнения является объектом. Похоже, что перегрузки операторов определяются во время компиляции, и во время компиляции все, что он знает, это то, что левая сторона является объектом. – MikeKulls 15 July 2012 в 23:53
  • 3
    @DominicCronin Я считаю, что ваш первый оператор верен в том, что == разрешит объект, но ваш второй оператор, который оператор перегружает, разрешает аналогичным образом. Они совершенно разные, поэтому .Equals будет разрешать строку в то время, когда == разрешит объект. – MikeKulls 16 July 2012 в 22:37
  • 4
    Чтобы быть ясным, тип object (обратите внимание на моноширинный шрифт) технически означает «выражение типа System.Object». Это не имеет никакого отношения к типу времени выполнения экземпляра, на который ссылается выражение. Я думаю, что оператор «определяемые пользователем» обрабатываются как virtual методы ». крайне вводит в заблуждение. Они обрабатываются как перегруженные методы и зависят только от типа экземпляров в режиме компиляции. Фактически, после вычисления набора определяемых пользователем операторов, остальная процедура связывания будет в точности методом алгоритма перегрузки метода – Mehrdad Afshari 16 July 2012 в 23:28
  • 5
    @DominicCronin Недопустимая часть заключается в том, что разрешение метода virtual зависит от фактического типа времени выполнения экземпляра, тогда как это полностью игнорируется при разрешении перегрузки оператора, и это действительно весь смысл моего ответа. – Mehrdad Afshari 17 July 2012 в 18:22

Я бы добавил, что если вы нарисуете свой объект на строку, то он будет работать правильно. Вот почему компилятор даст вам предупреждение:

Возможное непреднамеренное сравнение ссылок; чтобы получить сравнение значений, введите левую сторону для ввода «string»

12
ответ дан akjoshi 22 August 2018 в 14:16
поделиться
  • 1
    +1, потому что это только помогло мне понять, о чем идет речь в целом! – Dominic Cronin 19 November 2011 в 23:13
  • 2
    В точку. @DominicCronin: всегда соблюдайте предупреждения времени компиляции. Если у вас есть object expr = XXX; if (expr == "Energy") { ... }, то, поскольку левая сторона имеет тип времени компиляции object, компилятор должен использовать перегрузку operator ==(object, object). Он проверяет ссылочное равенство. Невозможно предсказать, будет ли это дано true или false из-за интернирования строк . Если вы знаете , левая сторона либо null, либо тип string, перед использованием == отдайте левую сторону в string. – Jeppe Stig Nielsen 13 February 2014 в 11:46
  • 3
    поместить часть этого другого пути. == (при определении того, использует ли он ссылочное равенство или равенство значения) зависит от типа времени компиляции / статического типа / левой стороны. (это тип, который разрешен при анализе времени компиляции). Вместо типа времени выполнения / динамического типа / типа RHS. Код BlueMonkMN показывает, что, хотя и не с кастингом. – barlop 22 April 2014 в 13:53

При сравнении ссылки объекта на строку (даже если ссылка на объект ссылается на строку), особое поведение оператора ==, специфичного для класса строк, игнорируется.

Обычно (когда не имея дело со строками, то есть), Equals сравнивает значения, а == сравнивает ссылки на объекты. Если два объекта, которые вы сравниваете, ссылаются на один и тот же точный экземпляр объекта, то оба будут возвращать true, но если один имеет тот же контент и поступает из другого источника (это отдельный экземпляр с теми же данными), то только Equals будут return true. Однако, как отмечено в комментариях, строка является особым случаем, потому что она переопределяет оператор ==, так что при использовании чисто ссылок на строки (а не ссылок на объекты) сравниваются только значения, даже если они являются отдельными экземплярами. Следующий код иллюстрирует тонкие различия в поведении:

string s1 = "test";
string s2 = "test";
string s3 = "test1".Substring(0, 4);
object s4 = s3;
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s2), s1 == s2, s1.Equals(s2));
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s3), s1 == s3, s1.Equals(s3));
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s4), s1 == s4, s1.Equals(s4));

Выход:

True True True
False True True
False False True
243
ответ дан BlueMonkMN 22 August 2018 в 14:16
поделиться
  • 1
    Пятно на. Оператор '==' сравнивает ссылки на объекты (неглубокое сравнение), тогда как .Equals () сравнивает содержание объектов (глубокое сравнение). Как сказал @mehrdad, .Equals () переопределяется, чтобы обеспечить глубокое сравнение контента. – Andrew 2 May 2009 в 14:43
  • 2
    Я останусь здесь, потому что считаю важным подчеркнуть, что происходит not , так как вы должны уделять пристальное внимание, чтобы понять это. (И я думаю, что код, демонстрирующий правильное и неправильное понимание, тоже стоит.) Я надеюсь, что рейтинг не опустится ниже 0. – BlueMonkMN 2 May 2009 в 15:39
  • 3
    Конечно, String реализует собственный пользовательский оператор. Если бы он этого не сделал, использование == не сравнивало бы содержимое. Так что String - плохой пример для использования здесь, так как это не помогает нам понять общий случай, когда пользовательский оператор не был определен. – Dominic Cronin 19 November 2011 в 23:07
  • 4
    +1 для примера эпического кода, что заставило меня понять это. Показывает общий случай статического типа (тип левой руки), являющегося объектом, и конкретным случаем статического типа (/ тип RHS), являющегося строкой. И хорошо подходит для интернирования строк. – barlop 22 April 2014 в 13:55
  • 5
    @Trisped Хорошая точка; Я обновил формулировку. Надеюсь, это яснее. – BlueMonkMN 27 January 2016 в 22:22
  • 6
    – Alexander Derck 31 January 2017 в 23:57

Во-первых, есть разность. Для чисел

> 2 == 2.0
True

> 2.Equals(2.0)
False

И для строк

> string x = null;
> x == null
True

> x.Equals(null)
NullReferenceException

В обоих случаях == ведет себя более полезно, чем .Equals

16
ответ дан Colonel Panic 22 August 2018 в 14:16
поделиться
  • 1
    Я не уверен, что я считаю, что принуждение интегральных типов к типам с плавающей точкой с оператором == является хорошим. Например, должно ли 16777216.0f равно (int) 16777217, (double) 16777217.0, обоих или ни одного? Сравнение между интегральными типами является точным, но сравнение с плавающей запятой должно выполняться только ИМХО со значениями, которые явно передаются в соответствующие типы. Сравнение a float с чем-то другим, кроме float или double с чем-то другим, кроме double, поражает меня как основного запаха кода, который не следует компилировать без диагностики. – supercat 16 August 2013 в 21:20
  • 2
    @supercat Я согласен - это огорчает, что x == y не подразумевает x/3 == y/3 (попробуйте x = 5 и y = 5.0). – Colonel Panic 19 August 2013 в 09:24
  • 3
    Я считаю, что использование / для целочисленного деления является дефектом в дизайне C # и Java. Паскаль div и даже VB.NET ` are much better. The problems with == `хуже, хотя: x==y и y==z не подразумевают, что x==z (рассмотрим три числа в моем предыдущем комментарии). Что касается отношения, которое вы предлагаете, даже если x и y оба float или оба double, x.equals((Object)y) не означает, что 1.0f/x == 1.0f / y` (если бы у меня были мои барабанщики, это гарантировало бы это, даже если == не различает положительные и нулевые значения Equals). – supercat 23 August 2013 в 22:20
  • 4
    Это нормально, потому что первый параметр Equals () - это строка! – Whiplash 12 December 2016 в 21:31

Когда мы создаем какой-либо объект, в объекте есть две части, одна из которых является контентом, а другая - ссылкой на этот контент. == сравнивает как контент, так и ссылку; equals() сравнивает только контент

http://www.codeproject.com/Articles/584128/What-is-the-difference-between-equalsequals- and-Eq

-1
ответ дан CT Zhu 22 August 2018 в 14:16
поделиться
  • 1
    Это неправда. Если a и b являются строковыми ссылками, то результат a == b не зависит от того, ссылаются ли ссылки на один и тот же объект. – phoog 8 January 2015 в 17:39

Поскольку статическая версия метода .Equal не упоминалась до сих пор, я хотел бы добавить это здесь, чтобы суммировать и сравнить 3 варианта.

MyString.Equals("Somestring"))          //Method 1
MyString == "Somestring"                //Method 2
String.Equals("Somestring", MyString);  //Method 3 (static String.Equals method) - better

, где MyString переменная, которая приходит откуда-то еще в коде.

Фоновая информация и summerize:

В Java, использующем == для сравнения строк, не следует использовать. Я упоминаю об этом, если вам нужно использовать оба языка, а также сообщить, что с помощью == можно также заменить что-то лучше на C #.

В C # нет никакой практической разницы для сравнения строк с использованием метода 1 или метода 2, если оба имеют строку типа. Однако, если один из них является нулевым, один имеет другой тип (например, целое число) или один представляет объект, который имеет другую ссылку, то, как показывает первоначальный вопрос, может возникнуть впечатление, что сравнение содержимого для равенства может не вернуть вы ожидаете.

Предлагаемое решение:

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

   bool areEqual = String.Equals("Somestring", MyString);  

Это немного больше, чтобы писать, но в мое мнение, безопаснее использовать.

Вот некоторая информация, скопированная из Microsoft:

public static bool Equals (string a, string b);

Параметры

a String

Первая строка для сравнения или null.

b String

Вторая строка для сравнения или null.

Возвращает Boolean

true, если значение a совпадает с значением b; в противном случае false. Если оба a и b равны null, метод возвращает true.

2
ответ дан Immac 22 August 2018 в 14:16
поделиться

== и .Equals зависят от поведения, определенного в фактическом типе и фактическом типе на сайте вызова. Оба являются просто методами / операторами, которые могут быть переопределены на любом типе и заданы любым поведением, которое автор так желает. По моему опыту, я считаю, что люди обычно реализуют .Equals на объекте, но пренебрегают имплементацией оператора ==. Это означает, что .Equals будет фактически измерять равенство значений, а == будет измерять, являются ли они одной и той же ссылкой.

Когда я работаю с новым типом, определение которого в потоке или написанием общих алгоритмов, я считаю, что наилучшей практикой является следующий

  • Если я хочу сравнить ссылки в C # я использую Object.ReferenceEquals напрямую (не требуется в общем случае)
  • Если я хочу сравнивать значения, я использую EqualityComparer<T>.Default

. В некоторых случаях, когда Я чувствую, что использование == неоднозначно. Я явно использую Object.Reference в коде для удаления двусмысленности.

Эрик Липперт недавно сделал сообщение в блоге по вопросу о том, почему существует 2 метода равенство в CLR. Это стоит прочитать

41
ответ дан JLILI Amen 22 August 2018 в 14:16
поделиться
  • 1
    Ну, Джаред, вы прямо нарушаете знаменитый Джеффа «Лучший код вообще не является кодом». Действительно ли это оправдано? С другой стороны, я могу видеть, откуда это происходит, и почему было бы желательно сделать семантику явной. В этом случае я очень предпочитаю, чтобы VB имел дело с равенством объектов. Это короткий и однозначный. – Konrad Rudolph 2 May 2009 в 14:51
  • 2
    @ Konrad, я действительно должен был сказать «когда я незнакомый с типом, я считаю, что лучшая практика следующая». Да, VB имеет гораздо лучшую семантику здесь, потому что она действительно разделяет ценность и ссылочное равенство. C # смешивает два вместе и иногда вызывает ошибки неоднозначности. – JaredPar 2 May 2009 в 15:04
  • 3
    Это не совсем правда. == нельзя переопределить, это статический метод. Это может быть только перегружено, что является важным отличием. Таким образом, код, который выполняется для оператора ==, связан во время компиляции, а Equals - виртуальный и найден во время выполнения. – Stefan Steinegger 15 August 2013 в 07:54

== Оператор 1. Если операнды Типы значений и их значения равны, он возвращает true else false. 2. Если операнды Reference Types , за исключением строки, и оба относятся к одному и тому же объекту, он возвращает true else false. 3. Если операнды являются строковыми типами, а их значения равны, он возвращает true else false.

.Equals 1. Если операнды являются ссылочными типами, он выполняет Reference Equality , который есть, если оба относятся к одному и тому же объекту, он возвращает true else false. 2. Если Операнды являются типами значений, то в отличие от оператора ==, он сначала проверяет их тип, и если их типы одинаковы, он выполняет == operator else, он возвращает false.

8
ответ дан kashif 22 August 2018 в 14:16
поделиться
  • 1
    Это неверно. Оператор == может быть перегружен для любого типа, а не только для строки. Описывая исключительное исключение только для строки, искажает семантику оператора. Было бы более точным, хотя, возможно, и не очень полезным, сказать «если операнды являются ссылочными типами, он возвращает true, если операнды относятся к одному и тому же объекту, если не существует применимой перегрузки, и в этом случае реализация этой перегрузки определяет результат & Quot ;. То же самое верно для Equals с добавленным усложнением, что это виртуальный метод, поэтому его поведение можно переопределить, а также перегрузить. – phoog 8 January 2015 в 17:35

Существует еще одно измерение для более раннего ответа от @BlueMonkMN. Дополнительное измерение состоит в том, что ответ на вопрос о названии @ Drahcir, как указано, также зависит от , как мы пришли к значению string. Для иллюстрации:

string s1 = "test";
string s2 = "test";
string s3 = "test1".Substring(0, 4);
object s4 = s3;
string s5 = "te" + "st";
object s6 = s5;
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s2), s1 == s2, s1.Equals(s2));

Console.WriteLine("\n  Case1 - A method changes the value:");
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s3), s1 == s3, s1.Equals(s3));
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s4), s1 == s4, s1.Equals(s4));

Console.WriteLine("\n  Case2 - Having only literals allows to arrive at a literal:");
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s5), s1 == s5, s1.Equals(s5));
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s6), s1 == s6, s1.Equals(s6));

Выход:

True True True

  Case1 - A method changes the value:
False True True
False False True

  Case2 - Having only literals allows to arrive at a literal:
True True True
True True True
2
ответ дан LearnCocos2D 22 August 2018 в 14:16
поделиться

Насколько я понимаю, ответ прост:

  1. == сравнивает ссылки на объекты.
  2. .Equals сравнивает содержимое объекта.
  3. String datatypes всегда действуют как сравнение контента.

Надеюсь, я прав и ответил на ваш вопрос.

8
ответ дан Liraz Shaka Amir 22 August 2018 в 14:16
поделиться

Действительно большие ответы и примеры!

Я хотел бы просто добавить фундаментальное различие между двумя,

. Операторы, такие как ==, не являются полиморфными, а Equals is

С учетом этой концепции, если вы выработаете какой-либо пример (просмотрев ссылочный тип левой руки и правой руки и проверив / зная, действительно ли тип имеет == оператор перегружен и Equals override), вы обязательно получите правильный ответ.

0
ответ дан Manish Basantani 22 August 2018 в 14:16
поделиться

Я немного смущен. Если тип содержимого времени выполнения имеет строку типа, то оба == и Equals должны возвращать значение true. Однако, поскольку это не так, тогда тип времени выполнения не является строкой, а вызов Equals на нем выполняет ссылочное равенство, и это объясняет, почему Equals («Energy Attack») терпит неудачу. Однако во втором случае решение о том, какой перегруженный == статический оператор следует вызывать, выполняется во время компиляции, и это решение выглядит как (строка, строка). это говорит мне, что Content обеспечивает неявное преобразование в строку.

2
ответ дан Mehmet Aras 22 August 2018 в 14:16
поделиться
  • 1
    У вас есть это обратно. Для начала Equals («Energy Attack») не прерывается, == это тот, который возвращает false. Ошибка ==, потому что она использует объект from, а не строку. – MikeKulls 11 August 2011 в 04:33
  • 2
    По умолчанию оператор == проверяет ссылочное равенство, определяя, указывают ли две ссылки на один и тот же объект. Поэтому ссылочные типы не должны реализовывать оператор ==, чтобы получить эту функциональность. Если тип неизменен, то есть данные, которые содержатся в экземпляре, не могут быть изменены, перегрузка оператора == для сравнения равенства значений вместо ссылочного равенства может быть полезна, поскольку в качестве неизменяемых объектов их можно считать такими же длинными поскольку они имеют одинаковую ценность. Не рекомендуется переопределять оператор == в неизменяемых типах. – 01010111 01010011 30 December 2011 в 08:14

==

Оператор == может использоваться для сравнения двух переменных любого типа и просто сравнивает биты.

int a = 3;
byte b = 3;
if (a == b) { // true }

Примечание: в левой части int больше нолей, но здесь нас здесь не интересует.

int a (00000011) == byte b (00000011)

Помните, что оператор-оператор заботится только о шаблоне бит в переменной.

Использовать == Если две ссылки (примитивы) относятся к одному и тому же объекту в куче.

Правила то же, является ли переменная ссылкой или примитивной.

Foo a = new Foo();
Foo b = new Foo();
Foo c = a;

if (a == b) { // false }
if (a == c) { // true }
if (b == c) { // false }

a == c истинно a == b является ложным

, битовая диаграмма одинакова для a и c, поэтому они равны с использованием ==.

Equal ():

Используйте метод equals (), чтобы увидеть, равны ли два разных объекта.

Такие, как два разных объекта String, которые оба представляют символы в «Jane»

-2
ответ дан Sanchit 22 August 2018 в 14:16
поделиться
  • 1
    Это неверно. Рассмотрим следующее: object a = 3; object b = 3; Console.WriteLine(a == b);. Выходной сигнал является ложным, хотя битовые шаблоны значений одинаковы. Также важны типы операндов. Причина, по которой нам «не волнует», о различном количестве нулей в вашем примере является то, что к тому времени, когда мы вызываем оператор equals, число нулей фактически такое же , из-за неявного преобразования. – phoog 8 January 2015 в 18:11

Добавление еще одной точки в ответ.

.EqualsTo() метод дает вам возможность сравнивать с культурой и чувствительностью к регистру.

2
ответ дан shA.t 22 August 2018 в 14:16
поделиться

Маркер == в C # используется для двух разных операторов проверки равенства. Когда компилятор встречает этот токен, он проверяет, осуществил ли какой-либо из сравниваемых типов перегрузку оператора равенства или для сравнения отдельных типов комбинации (*), или для комбинации типов, к которым могут быть преобразованы оба типа. Если компилятор найдет такую ​​перегрузку, он будет использовать его. В противном случае, если оба типа являются ссылочными типами, и они не являются несвязанными классами (либо они могут быть интерфейсом, либо они могут быть связанными классами), компилятор будет рассматривать == как оператор сравнения ссылок. Если ни одно из условий не применяется, компиляция не будет выполнена.

Обратите внимание, что некоторые другие языки используют отдельные токены для двух операторов проверки равенства. Например, в VB.NET токен = используется в выражениях исключительно для перегружаемого оператора проверки равенства, а Is используется в качестве оператора эталонного теста или нулевого теста. An использовать = для типа, который не переопределяет оператор проверки равенства, не будет работать, как будет пытаться использовать Is для любых целей, кроме проверки ссылочного равенства или недействительности.

(*) Типы обычно только перегружают равенство для сравнения с самим собой, но может быть полезно, чтобы типы перегружали оператор равенства для сравнения с другими конкретными типами; например, int мог бы (и IMHO должен был иметь, но не сделал) определил операторы равенства для сравнения с float, так что 16777217 не сообщил бы себя равным 16777216f. Как бы то ни было, поскольку такой оператор не определен, C # будет продвигать int до float, округляя его до 16777216f, прежде чем оператор проверки равенства увидит его; этот оператор затем видит два равных числа с плавающей запятой и сообщает о них как о равных, не подозревая о округлении, которое имело место.

0
ответ дан supercat 22 August 2018 в 14:16
поделиться
  • 1
    Вместо того, чтобы иметь значение false для сравнения int-to-float, я предпочитаю подход, который использует F #, который вообще запрещает такое сравнение. Затем программист может решить, как и как обрабатывать тот факт, что значения имеют другой тип. Потому что иногда, в конце концов, мы do хотим рассматривать 3 как равные 3.0f. Если мы требуем, чтобы программист сказал, что предназначено в каждом случае, тогда нет опасности поведения по умолчанию, приводящего к непреднамеренным результатам, поскольку поведение по умолчанию отсутствует. – phoog 8 January 2015 в 18:27
  • 2
    @phoog: Мое личное чувство заключается в том, что языки должны иметь свой «нормальный». средства проверки равенства реализуют отношение эквивалентности и запрещают все комбинации операндов, для которых это не будет. Я не вижу огромного преимущества наличия равенства проверки языка между целыми числами и поплавками, подтверждая, что float точно представляет целое число, которое соответствует int, или просто запрещает такие сравнения, но будет рассматривать любой подход, превосходящий выполнение языка преобразование с потерями перед сравнением. – supercat 12 January 2015 в 18:06

Единственное различие между Equal и == заключается в сравнении типов объектов. в других случаях, таких как ссылочные типы и типы значений, они почти одинаковы (либо оба являются поразрядным равенством, либо оба являются ссылочным равенством).

object: Equals: bit-wise равенство ==: reference равенство

string: (equals и == одинаковы для строки, но если одна из строк была изменена на объект, тогда результат сравнения будет разным). Равны: побитовое равенство ==: битовое равенство

Подробнее см. здесь .

-2
ответ дан Will Yu 22 August 2018 в 14:16
поделиться
  • 1
    Object.Equals не обязательно смотрит на поразрядное равенство. Это виртуальный метод, и переопределение может делать все, что захочет. – phoog 8 January 2015 в 17:44
  • 2
    да, вы правы, вы можете делать все, что хотите, переопределить. но тема, о которой мы говорим, является реализацией по умолчанию. по умолчанию реализация Object.Equals является поразрядным равенством. – Will Yu 8 January 2015 в 19:14
Другие вопросы по тегам:

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