Database
 sql >> Baza danych >  >> RDS >> Database

Porównywanie obiektów według wartości. Część 6:Wdrażanie równości struktury

Przeanalizowaliśmy już osobliwości struktur platformy .NET, które reprezentują typy wartości podczas porównywania obiektów według wartości – instancje struktur.

Teraz opiszę ten proces na konkretnym przykładzie, aby sprawdzić, czy pozwoli nam to ogólnie określić zastosowanie porównania obiektów po wartości, a tym samym uprościć próbkę porównywania obiektów po wartości – instancje klas reprezentujące referencję typy.

Struktura PersonStruct:

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);
    }
}

Jak widać, ten przykład jest mniejszy i łatwiejszy ze względu na strukturę, ponieważ instancje struktur nie mają wartości null i nie można dziedziczyć ze struktur zdefiniowanych przez użytkownika. Omówiliśmy już osobliwości implementacji porównania według wartości dla instancji klas w moim poprzednim artykule.

Dodatkowo wyznaczyliśmy pola do porównania obiektów oraz zaimplementowaliśmy metodę GetHashCode().

Metody i operatory porównania zostały zaimplementowane w następującej kolejności:

  1. Aby porównać dwa wystąpienia struktur, zaimplementowaliśmy metodę statyczną PersonStruct.Equals(PersonStruct, PersonStruct). Użyjemy tej metody jako metody porównawczej referencji podczas implementacji innych metod i operatorów. Dodatkowo może być stosowany do porównywania wystąpień struktur w językach, które nie obsługują operatorów.
  2. Operatory PersonStruct.==(PersonStruct, PersonStruct) i PersonStruct.!=(PersonStruct, PersonStruct) również zostały zaimplementowane. Należy zauważyć, że kompilator C# ma następujące cechy szczególne:
  • Możesz porównać z przeciążonymi operatorami T.==(T, T) i T.!=(T, T) w Nullable(Of T)
  • Przed sprawdzeniem równości wartości kompilator może sprawdzić, czy wystąpienia struktur mają prawidłową wartość. Ponadto kompilator nie opakowuje instancji struktur w obiekty.
  • Tak więc porównywanie wystąpień struktury Nullable(Of T) z niewpisaną wartością dopuszczającą wartość null prowadzi do wywołania operatorów ==(T, T) lub T.!=(T, T) podczas porównywania wystąpień Nullable( Of T) struktura bez przeciążonych operatorów T.==(T, T) i T.!=(T, T) powoduje wywołanie operatorów Object.==(Object, Object) lub Object.!=(Object, Object) i w rezultacie zawijając instancję w obiekt.
  1. Metoda PersonStruct.Equals(PersonStruct) (implementacja IEquatable(Of PersonStruct)) została zaimplementowana poprzez wywołanie metody PersonStruct.Equals(PersonStruct, PersonStruct).
  2. Aby uniknąć zawijania instancji struktur w obiekty, gdy mamy jedną lub dwie instancje Nullable(Of PersonStruct), możliwe jest zaimplementowanie następujących metod:
  • PersonStruct.Equals(PersonStruct?, PersonStruct?), jako wywołanie operatora PersonStruct.==(PersonStruct, PersonStruct) służy do uniknięcia zawijania wystąpień struktur obu argumentów w obiekty i wywoływania Object.Equals( Metoda Object, Object), jeśli co najmniej jeden z argumentów jest wystąpieniem Nullable(Of PersonStruct). Ponadto można użyć tej metody do porównywania wystąpień Nullable(Of PersonStruct) w językach, które nie obsługują operatorów. W kodzie można znaleźć komentarze wyjaśniające, jak można zaimplementować tę metodę, jeśli kompilator C# nie był w stanie użyć operatorów T.==(T, T) i T.!=(T, T) dla wartości Nullable(Of T) argumenty.
  • PersonStruct.Equals(PersonStruct?) – implementacja interfejsu IEquatable(Of PersonStruct?) służąca do uniknięcia zawijania argumentów Nullable(Of PersonStruct) w obiekty i wywoływania metody PersonStruct.Equals(Object). Jest zaimplementowany jako wywołanie operatora PersonStruct.==(PersonStruct, PersonStruct) z komentowanym kodem do użycia operatorów T.==(T, T) i T.!=(T, T) dla Nullable(Of T ) argumenty.
  • PersonStruct.Equals(Object) – nadpisuje metodę Object.Equals(Object). Jest to implementowane przez sprawdzenie zgodności typu argumentu z typem bieżącego obiektu za pomocą operatora is przez rzutowanie argumentu na PersonStruct i wywołanie PersonStruct.Equals(PersonStruct, PersonStruct).

Uwagi:

  • Implementacja interfejsu IEquatable(Of PersonStruct?) — IEquatable(Of Nullable(Of PersonStruct)) służy do pokazania konkretnych problemów na platformie podczas pracy ze strukturami, w których zawijanie instancji w obiekty odbywa się szybciej niż się spodziewamy.
  • W realnych projektach, o ile nie jest konieczne poprawianie wydajności, implementacja IEquatable(Of Nullable(Of T)) nie ma zastosowania ze względów architektonicznych – nie powinniśmy implementować wpisanego IEquatable w typie T dla żadnego typu.
  • Ogólnie rzecz biorąc, nie jest konieczne przytłaczanie kodu różnymi optymalizacjami.

W przypadku struktur możemy osiągnąć znacznie prostsze i bardziej wydajne porównywanie według wartości, unikając dziedziczenia struktur zdefiniowanych przez użytkownika i konieczności sprawdzania obiektów pod kątem wartości null. Ponadto możemy monitorować nową logikę, która obsługuje argumenty Nullable(Of T).

W mojej przyszłej publikacji podsumuję następujące punkty:

  • Kiedy dobrym pomysłem jest zaimplementowanie porównywania obiektów według wartości;
  • Jak możemy uprościć implementację porównania według wartości dla obiektów – instancje klas, które reprezentują typy referencyjne.

Przeczytaj także:

Porównywanie obiektów według wartości. Część 1:Początek

Porównywanie obiektów według wartości. Część 2:Uwagi dotyczące implementacji metody równości

Porównywanie obiektów według wartości. Część 3:Równa specyficzne dla typu i operatory równości

Porównywanie obiektów według wartości. Część 4:Operatory dziedziczenia i porównania

Porównywanie obiektów według wartości. Część 5:Kwestia równości struktury


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Co to jest ODBC?

  2. Wskazówki dotyczące rozmowy kwalifikacyjnej z administratorem bazy danych SQL

  3. Czym jest schemat w SQL i jak go stworzyć?

  4. Sekwencyjne prędkości i posuwy

  5. Łączenie z Vertica w IRI Workbench