In the previous publication, we reviewed the features of the device and operation of the structures of the .NET platform, which are "types by value" (Value Types) in the context of comparison by the value of objects - instances of structures .
Now we will consider a ready-made example of the implementation of comparison by the value of objects - instances of structures .
Will the example for structures help to more accurately determine from the subject (domain) point of view the scope of comparison of objects by value as a whole, and thereby simplify the comparison pattern by value of objects - instances of classes that are Reference Types , derived in one of the previous publications ?
PersonStruct structure:
using System; namespace HelloEquatable { public struct PersonStruct : IEquatable<PersonStruct>, IEquatable<PersonStruct?> { private static int GetHashCodeHelper(int[] subCodes) { int result = subCodes[0]; for (int i = 1; i < subCodes.Length; i++) result = unchecked(result * 397) ^ subCodes[i]; return result; } private static string NormalizeName(string name) => name?.Trim() ?? string.Empty; private static DateTime? NormalizeDate(DateTime? date) => date?.Date; public string FirstName { get; } public string LastName { get; } public DateTime? BirthDate { get; } public PersonStruct(string firstName, string lastName, DateTime? birthDate) { this.FirstName = NormalizeName(firstName); this.LastName = NormalizeName(lastName); this.BirthDate = NormalizeDate(birthDate); } public override int GetHashCode() => GetHashCodeHelper( new int[] { this.FirstName.GetHashCode(), this.LastName.GetHashCode(), this.BirthDate.GetHashCode() } ); public static bool Equals(PersonStruct first, PersonStruct second) => first.BirthDate == second.BirthDate && first.FirstName == second.FirstName && first.LastName == second.LastName; public static bool operator ==(PersonStruct first, PersonStruct second) => Equals(first, second); public static bool operator !=(PersonStruct first, PersonStruct second) => !Equals(first, second); public bool Equals(PersonStruct other) => Equals(this, other); public static bool Equals(PersonStruct? first, PersonStruct? second) => first == second; // Alternate version: //public static bool Equals(PersonStruct? first, PersonStruct? second) => // first.HasValue == second.HasValue && // ( // !first.HasValue || Equals(first.Value, second.Value) // ); public bool Equals(PersonStruct? other) => this == other; // Alternate version: //public bool Equals(PersonStruct? other) => // other.HasValue && Equals(this, other.Value); public override bool Equals(object obj) => (obj is PersonStruct) && Equals(this, (PersonStruct)obj); // Alternate version: //public override bool Equals(object obj) => // obj != null && // this.GetType() == obj.GetType() && // Equals(this, (PersonStruct)obj); } }
An example with the implementation of comparing objects by value for structures smaller in size and simpler in structure due to the fact that instances of structures cannot accept null values and the fact that it is impossible to inherit from user-defined structures (User defined structs) the value of objects - instances of classes, taking into account inheritance, are considered in the fourth publication of this cycle).
Similar to the previous examples, the fields for comparison are defined and the GetHashCode () method is implemented.
Methods and comparison operators are implemented sequentially as follows:
The static method PersonStruct.Equals (PersonStruct, PersonStruct) is implemented to compare two instances of structures.
This method will be used as a reference comparison method when implementing other methods and operators.
This method can also be used to compare instances of structures in languages that do not support operators.
The PersonStruct. == (PersonStruct, PersonStruct) and PersonStruct.! = (PersonStruct, PersonStruct) operators are implemented.
It should be noted that the C # compiler has an interesting feature:
The PersonStruct.Equals (PersonStruct) method (implementation of IEquatable (Of PersonStruct)) is implemented by calling the PersonStruct.Equals method (PersonStruct, PersonStruct).
PersonStruct.Equals method (PersonStruct ?, PersonStruct?) - to prevent instances of structures of both arguments from packing into objects and calling Object.Equals (Object, Object) if at least one of the arguments is an instance of Nullable (Of PersonStruct). This method can also be used when comparing instances of Nullable (Of PersonStruct) in languages that do not support operators. The method is implemented as a call to the PersonStruct operator. == (PersonStruct, PersonStruct). Next to the method is a commented code showing how this method should have been implemented if the C # compiler did not support the above-mentioned "magic" of using the T operators. == (T, T) and T. = (T, T) for Nullable (Of T) -arguments.
The PersonStruct.Equals method (PersonStruct?) (Implementation of the IEquatable interface (Of PersonStruct?)) - to prevent the packaging of a Nullable (Of PersonStruct) argument in an object and to call the PersonStruct.Equals (Object) method. The method is also implemented as a call to the PersonStruct. == operator (PersonStruct, PersonStruct), with commented out implementation code in the absence of the compiler "magic".
Note:
For structures, the exhaustive implementation of comparing instances by value turned out to be much simpler and more compact due to the lack of inheritance in User defined structs, and also due to the absence of the need for checks for null .
(However, compared with the implementation for classes, a new logic has appeared that supports the Nullable (Of T) -arguments).
In the next publication we will summarize the cycle on the topic "Object Equality", incl. Consider:
Source: https://habr.com/ru/post/319100/
All Articles