2014-01-14 3 views
69

Почему этот код возвращает истину:Почему эти два сравнения имеют разные результаты?

new Byte() == new Byte() // returns true 

но этот код возвращает ложь:

new Byte[0] == new Byte[0] // returns false 
+12

См. Http://ericlippert.com/2014/01/15/inconsistent-equality/ –

+4

Я удивлен, что никто не нашел дубликатов для этого вопроса, так как он очень простой ** значение ** тип стихов ** ссылка * * тип вопрос. – P5Coder

+2

Я еще больше удивляюсь количеству голосов, которые у него есть - 51 на данный момент. – P5Coder

ответ

143

Поскольку new Byte() создает тип значения, которые сравниваются по значению (по умолчанию он будет возвращать byte со значением 0). И new Byte[0] создает массив, который является ссылочным типом и сравнивается по ссылке (и эти два экземпляра массива будут иметь разные ссылки).

См. Value Types and Reference Types артикул для деталей.

44

Байты: value types в .NET, что означает, что оператор == возвращает true тогда и только тогда, когда два байта имеют одинаковое значение. Это также известно как value equality.

Но массивы reference types в .NET, то есть оператор == возвращает true тогда и только тогда, когда они ссылаются на один и тот же экземпляр массива в памяти. Это также известно как reference equality or identity.

Обратите внимание, что оператор == может быть перегружен как для ссылочных, так и для значений. System.String, например, является ссылочным типом, но оператор == для строк сравнивает каждый символ в массиве в последовательности. См. Guidelines for Overloading Equals() and Operator == (C# Programming Guide).

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

+1

Я считаю, что суть вопроса заключается в '==' операторе и его двойной природе. Этот ответ явно охватывает это. –

+1

Самый правильный ответ, если только для «по умолчанию» –

+0

Мне нравится использование «по умолчанию» для других ссылочных типов, но действительно ли возможно изменить это поведение для типов массивов? –

10

Сравнение ссылки на самом деле сравнивает адрес указателя, который отличается от причины, возвращающей значение false и в значение, не имеет значения, что он сравнивает значение.

Компилятор попытается сохранить тип значения в регистрах, но из-за ограниченного числа регистров дальнейшее хранение происходит в стеке со значениями [Reference], в то время как тип Reference находится в стеке, но значение хранит адрес адреса памяти в куче.

Сравнение здесь сравнивает значение, присутствующее в стеке, которое в первом случае является одинаковым, а во втором случае это адреса кучи, которые различны.

reference

+5

Это довольно запутанный ответ. Первая часть по-прежнему делает его похожим на сравнительное сравнение, потому что вы все еще используете слово «Указатель». Использование графического или простого текста также раздражает, потому что мне очень сложно отредактировать его, чтобы улучшить ответ. –

+0

-1 для сохранения «значений типов хранятся в стеке». Я бы счел весьма вероятным, что результаты этих двух вызовов 'new Byte()' вероятно, хранятся в регистрах. –

+0

@Damien_The_Unbeliever Регистрировать хранилище зависит от наличия регистра, если он хранится в Stack, в обоих случаях значение такое же. –

1

Существует перегрузка == оператора, в котором оба операнда имеют тип byte и реализуется для сравнения значения каждого байта; в этом случае у вас есть два нулевых байта, и они равны.

== оператор не перегружен для массивов, поэтому используется перегрузка, имеющая два object операндов (так как массивы типа object) во втором случае, и его реализация сравнивает ссылки на два объект. Ссылка на два массива отличается.

Следует отметить, что это не имеет ничего общего с тем, что byte является типом значений, а массивы - ссылочными типами.Оператор == для byte имеет значение семантики только, потому что существует определенная перегрузка оператора с этой реализацией. Если эта перегрузка не существует, то будет перегрузки, для которой два байта будут действительными операндами, и поэтому код не будет компилироваться вообще. Вы можете увидеть это достаточно легко, создав пользовательский struct и сравнив два экземпляра его с оператором ==. Код не будет компилироваться, если вы не предоставите свою собственную реализацию == для этих типов.

Смежные вопросы