В предыдущей публикации мы вывели наиболее полный и корректный способ реализации сравнения по значению объектов — экземпляров классов (являющихся ссылочными типами — Reference Types) для платформы .NET. Каким образом нужно модифицировать предложенный способ для корректной реализации сравнения по значению объектов — экземпляров структур (являющихся "типами по значению" — Value Types)? Экземпляры структур, в силу своей природы, всегда сравниваются по значению. Для предопределенных типов, таких как Boolean или Int32, под сравнением по значению понимается сравнение непосредственно значений экземпляров структур. Если структура определена разработчиком — пользователем платформы (User defined struct), то сравнение по умолчанию автоматически реализуется как сравнение значений полей экземпляров структур. (Подробности см. в описании метода ValueType.Equals(Object) и операторов == и !=). Также при этом автоматически определенным образом реализуется метод ValueType.GetHashCode(), перекрывающий метод Object.GetHashCode(). При сравнении значений полей используется рефлексия, что влияет на производительность. Поле структуры может иметь не "значимый", а ссылочный тип, а в этом случае сравнение полей по ссылке может не подойти с предметной (доменной) точки зрения, и может потребоваться сравнение полей по значению (хотя в общем случае использование в структуре ссылочный полей можно считать неверным архитектурным решением).
(В документации рекомендуется создать для такой структуры собственную реализацию сравнения по значению для повышения производительности и наиболее точного отражения значения равенства для данного типа.) Может оказаться, что с предметной точки зрения не все поля должны участвовать в сравнении (хотя, опять же, для структур в общем случае это можно считать неверным решением). Таким образом, с одной стороны, есть несколько причин общего характера, подталкивающих к реализации у структур собственного механизма сравнения объектов по значению (производительность, соответствие доменной модели). С другой стороны, необходимость корректной реализации метода GetHashCode() автоматически приводит к необходимости реализации сравнения по значению, т.к. метод GetHashCode() в силу природы хеш-кода (см. первую публикацию) должен "знать", какие данные (поля) и как участвуют в сравнении по значению. С третьей стороны, возможен и особый случай, когда есть "простая" структура, состоящая, например, только из полей-структур, для которых побайтовое сравнение с помощью рефлексии заведомо дает семантически верный результат (например, Int32). В этом случае возможно реализовать GetHashCode() корректным образом (чтобы для равных объектов хеш-код всегда был один и тот же), не создавая при этом собственную реализацию сравнения по значению. Например: Однако, в случае переписывания этого простого примера с использованием "автоматически реализуемых свойств" картина выглядит менее ясной: В документации к "автосвойствам" говорится об автоматическом создании anonymous backing field, соответствующим публичным свойствам. Строго говоря, из описания неясно, будут ли равными с точки зрения дефолтной реализации сравнения по значению два объекта Point с попарно одинаковыми значениями X и Y: Что если в двух разных объектах создаются backing-поля с разными именами вида (x1, y1) и (x2, y2)?
Будет ли учитываться при сравнении, что x1 соответствует x2, а y1 соответствует y2? Скорее всего, где-то в недрах документации или книгах авторов, имеющих отношение к разработке платформы, можно найти положительные ответы на эти вопросы — в том смысле, что поведение для структур с явно объявленными полями и структур с автосвойствами будет давать одинаковый результат при дефолтном сравнении по значению. Либо, если какая-то часть окажется недокументированной, то, скорее всего, поведение компилятора и исполняющей среды окажется ожидаемым. С учетом общей совокупности аргументов, представляется, что в общем случае для структур предпочтительнее реализовывать собственное сравнение по значению. Развернутый пример с подробными комментариями, на основе знакомой по предыдущим публикациям сущности Person, рассмотрим в следующей публикации. Software Developer