В предыдущей публикации мы рассмотрели особенности устройства и работы структур платформы .NET, являющихся "типами по значению" (Value Types) в разрезе сравнения по значению объектов — экземпляров структур. Теперь рассмотрим готовый пример реализации сравнения по значению объектов — экземпляров структур. Поможет ли пример для структур более точно определить с предметной (доменной) точки зрения область применимости сравнения объектов по значению в целом, и тем самым упростить образец сравнения по значению объектов — экземпляров классов, являющихся ссылочными типами (Reference Types), выведенный в одной из предыдущих публикаций? Структура PersonStruct: Пример с реализацией сравнения объектов по значению для структур меньше по объему и проще по структуре благодаря тому, что экземпляры структур не могут принимать null-значения и тому, что от структур, определенных пользователем (User defined structs), нельзя унаследоваться (особенности реализации сравнения по значению объектов — экземпляров классов, с учетом наследования, рассмотрены в четвертой публикации данного цикла). Аналогично предыдущим примерам, определены поля для сравнения и реализован метод GetHashCode(). Методы и операторы сравнения реализованы последовательно следующим образом: Реализован статический метод PersonStruct.Equals(PersonStruct, PersonStruct) для сравнения двух экземпляров структур.
Этот метод будет использован как эталонный способ сравнения при реализации других методов и операторов.
Также этот метод может использоваться для сравнения экземпляров структур в языках, не поддерживающих операторы. Реализованы операторы PersonStruct.==(PersonStruct, PersonStruct) и PersonStruct.!=(PersonStruct, PersonStruct).
Следует отметить, что компилятор C# имеет интересную особенность: Реализован метод PersonStruct.Equals(PersonStruct) (реализация IEquatable(Of PersonStruct)), путем вызова метода PersonStruct.Equals(PersonStruct, PersonStruct). Метод PersonStruct.Equals(PersonStruct?, PersonStruct?) — для предотвращения упаковки экземпляров структур обоих аргументов в объекты и вызова метода Object.Equals(Object, Object), если хотя бы один из аргументов является экземпляром Nullable(Of PersonStruct). Также этот метод может быть использован при сравнении экземпляров Nullable(Of PersonStruct) в языках, не поддерживающих операторы. Метод реализован как вызов оператора PersonStruct.==(PersonStruct, PersonStruct). Рядом с методом приведен закомментированный код, показывающий, каким образом нужно было бы реализовать этот метод, если бы компилятор C# не поддерживал вышеупомянутую "магию" использования операторов T.==(T, T) и T.!=(T, T) для Nullable(Of T)-аргументов. Метод PersonStruct.Equals(PersonStruct?) (реализация интерфейса IEquatable(Of PersonStruct?)) — для предотвращения упаковки Nullable(Of PersonStruct)-аргумента в объект и вызова метода PersonStruct.Equals(Object). Метод также реализован как вызов оператора PersonStruct.==(PersonStruct, PersonStruct), с закомментированным кодом реализации при отсутствии "магии" компилятора. Примечание: Для структур исчерпывающая реализация сравнения экземпляров по значению получилась существенно проще и компактнее благодаря отсутствию наследования у User defined structs, а также благодаря отсутствию необходимости проверок на null.
(Однако, по сравнению с реализацией для классов, появилась и новая логика, поддерживающая Nullable(Of T)-аргументы). В следующей публикации мы подведем итоги цикла на тему "Object Equality", в т.ч. рассмотрим: Software Developer