sql >> Databáze >  >> RDS >> Database

Porovnávání objektů podle hodnoty. Část 6:Implementace rovnosti struktur

Již jsme analyzovali zvláštnosti struktur rozhraní .NET, které reprezentují typy hodnot při porovnávání objektů podle hodnoty – instance struktur.

Nyní popíšu tento proces na konkrétním příkladu, abychom si ověřili, zda nám umožní obecně určit použití porovnávání objektů podle hodnoty, a tím zjednodušit vzorek porovnávání objektů podle hodnoty – instance třídy, které představují referenci. 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 vidíte, tento příklad je menší a jednodušší strukturou, protože instance struktur nejsou null a není možné dědit z uživatelsky definovaných struktur. Již jsme diskutovali o zvláštnostech implementace porovnání podle hodnoty pro instance třídy v mém předchozím článku.

Kromě toho jsme určili pole pro porovnání objektů a implementovali metodu GetHashCode().

Metody a operátory porovnání byly implementovány v následujícím pořadí:

  1. Pro porovnání dvou instancí struktur jsme implementovali statickou metodu PersonStruct.Equals(PersonStruct, PersonStruct). Tuto metodu použijeme jako referenční srovnávací metodu při implementaci jiných metod a operátorů. Navíc jej lze použít k porovnání instancí struktur v jazycích, které nepodporují operátory.
  2. Byly implementovány také operátory PersonStruct.==(PersonStruct, PersonStruct) a PersonStruct.!=(PersonStruct, PersonStruct). Je třeba poznamenat, že kompilátor C# má následující zvláštnosti:
  • Můžete porovnat s přetíženými operátory T.==(T, T) a T.!=(T, T) v Nullable(Of T)
  • Před kontrolou rovnosti hodnot může kompilátor ověřit, zda instance struktur mají platnou hodnotu. Kompilátor navíc nezabaluje instance struktur do objektů.
  • Porovnávání instancí struktury Nullable(Of T) s nezadanou hodnotou s možností null vede k volání operátorů ==(T, T) nebo T.!=(T, T), zatímco porovnáváme instance Nullable( Struktura T) bez přetížených operátorů T.==(T, T) a T.!=(T, T) má za následek volání operátorů Object.==(Object, Object) nebo Object.!=(Object, Object) a v důsledku toho při zabalení instance do objektu.
  1. Metoda PersonStruct.Equals(PersonStruct) (implementace IEquatable(Of PersonStruct)) byla implementována voláním metody PersonStruct.Equals(PersonStruct, PersonStruct).
  2. Aby se předešlo zalamování instancí struktur do objektů, když máme jednu nebo dvě instance s možností Null(Of PersonStruct), je možné implementovat následující metody:
  • PersonStruct.Equals(PersonStruct?, PersonStruct?) jako volání operátoru PersonStruct.==(PersonStruct, PersonStruct) se používá k tomu, aby se zabránilo zalamování instancí struktur obou argumentů do objektů a volání Object.Equals( Object, Object), pokud je alespoň jeden z argumentů instancí Nullable(Of PersonStruct). Kromě toho můžete tuto metodu použít k porovnání instancí Nullable(Of PersonStruct) v jazycích, které nepodporují operátory. V kódu můžete najít komentáře vysvětlující, jak by tato metoda mohla být implementována, pokud kompilátor C# nebyl schopen použít operátory T.==(T, T) a T.!=(T, T) pro Nullable(Of T) argumenty.
  • PersonStruct.Equals(PersonStruct?) – implementace rozhraní IEquatable(Of PersonStruct?), které se používá k tomu, aby se zabránilo zabalení argumentů Nullable(Of PersonStruct) do objektů a volání metody PersonStruct.Equals(Object). Je implementován jako volání operátoru PersonStruct.==(PersonStruct, PersonStruct) s komentovaným kódem pro použití operátorů T.==(T, T) a T.!=(T, T) pro Nullable(Of T) ) argumenty.
  • PersonStruct.Equals(Object) – přepíše metodu Object.Equals(Object). Je implementován kontrolou kompatibility typu argumentu s typem aktuálního objektu pomocí operátoru is přetypováním argumentu do PersonStruct a voláním PersonStruct.Equals(PersonStruct, PersonStruct).

Poznámky:

  • Implementace rozhraní IEquatable(Of PersonStruct?) — IEquatable(Of Nullable(Of PersonStruct)) slouží k zobrazení konkrétních problémů na platformě při práci se strukturami, kdy k zalamování instancí do objektů dochází rychleji, než očekáváme.
  • V reálných projektech, za předpokladu, že není nutné zlepšit výkon, není implementace IEquatable(Of Nullable(Of T)) z architektonických důvodů použitelná – neměli bychom implementovat typované IEquatable v typu T pro žádný typ.
  • Obecně není nutné kód zahltit různými optimalizacemi.

U struktur bychom mohli dosáhnout mnohem jednoduššího a produktivnějšího porovnání podle hodnoty tím, že se vyhneme dědění uživatelsky definovaných struktur a nutnosti kontrolovat objekty na null. Kromě toho můžeme sledovat novou logiku, která podporuje argumenty Nullable(Of T).

Ve své budoucí publikaci shrnu následující body:

  • kdy je dobré implementovat porovnání objektů podle hodnoty;
  • Jak můžeme zjednodušit implementaci porovnání podle hodnoty pro objekty – instance tříd, které představují referenční typy.

Přečtěte si také:

Porovnávání objektů podle hodnoty. Část 1:Začátek

Porovnávání objektů podle hodnoty. Část 2:Poznámky k implementaci metody Equals

Porovnávání objektů podle hodnoty. Část 3:Typově specifické operátory rovnosti a rovnosti

Porovnávání objektů podle hodnoty. Část 4:Operátory dědičnosti a porovnávání

Porovnávání objektů podle hodnoty. Část 5:Problém rovnosti struktur


  1. RoR:Nelze změnit_sloupec v postgresu, v pořádku v MySQL (MySQL pro vývoj, Postgres na Heroku)

  2. Snadný způsob, jak nasadit MySQL Galera Cluster na AWS

  3. Použití mysql concat() v klauzuli WHERE?

  4. SQLite JSON()