sql >> Databasteknik >  >> RDS >> Database

Jämföra objekt efter värde. Del 6:Struktur Jämställdhetsimplementering

Vi har redan analyserat särdragen hos strukturer i .NET-ramverket som representerar värdetyper när man jämför objekt efter värde – förekomst av strukturer.

Nu ska jag beskriva denna process på ett särskilt exempel för att kontrollera om det kommer att tillåta oss att bestämma användningen av objektjämförelsen efter värde i allmänhet och därmed förenkla ett urval av jämförelser av objekt efter värde - klassinstanser som representerar referens typer.

PersonStruct-strukturen:

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

Som du kan se är det här exemplet mindre och enklare till sin struktur, eftersom instanser av strukturer inte är null och det inte är möjligt att ärva från användardefinierade strukturer. Vi har redan diskuterat egenheter för att implementera jämförelsen efter värde för klassinstanserna i min tidigare artikel.

Dessutom har vi bestämt fält för objektjämförelse samt implementerat GetHashCode()-metoden.

Metoder och operatörer för jämförelse har implementerats i följande ordning:

  1. För att jämföra två instanser av strukturer har vi implementerat den statiska metoden PersonStruct.Equals(PersonStruct, PersonStruct). Vi kommer att använda denna metod som en referensjämförelsemetod när vi implementerar andra metoder och operatörer. Dessutom kan den användas för att jämföra instanser av strukturer på språk som inte stöder operatörer.
  2. Operatorerna PersonStruct.==(PersonStruct, PersonStruct) och PersonStruct.!=(PersonStruct, PersonStruct) har också implementerats. Det bör noteras att en C#-kompilator har följande egenheter:
  • Du kan jämföra med de överbelastade operatorerna T.==(T, T) och T.!=(T, T) i Nullable(Of T)
  • Innan du kontrollerar en värdelikhet kan en kompilator verifiera om instanser av strukturer har ett giltigt värde. Dessutom lindar en kompilator inte in instanser av strukturer i objekt.
  • Jämförelse av instanser av Nullable(Of T)-strukturen med ett otypat nullvärde leder alltså till att operatorerna ==(T, T) eller T.!=(T, T) anropas, samtidigt som instanser av Nullable( jämförs) Av T) struktur utan överbelastade operatorer T.==(T, T) och T.!=(T, T) resulterar i anrop av operatorerna Objekt.==(Objekt, Objekt) eller Objekt.!=(Objekt, Objekt) och, som ett resultat, att en instans lindas in i objektet.
  1. Metoden PersonStruct.Equals(PersonStruct) (implementering av IEquatable(Of PersonStruct)) har implementerats genom att anropa metoden PersonStruct.Equals(PersonStruct, PersonStruct).
  2. För att undvika att omsluta instanser av strukturer till objekt, när vi har en eller två Nullable(Of PersonStruct)-instanser, är det möjligt att implementera följande metoder:
  • PersonStruct.Equals(PersonStruct?, PersonStruct?), som ett anrop till operatorn PersonStruct.==(PersonStruct, PersonStruct), används för att undvika att linda in instanser av strukturer av båda argumenten till objekt och anropa Object.Equals( Object, Object) om minst ett av argumenten är en Nullable(Of PersonStruct)-instans. Dessutom kan du använda den här metoden för att jämföra Nullable(Of PersonStruct)-instanser på språk som inte stöder operatorer. I koden kan du hitta kommentarer som förklarar hur denna metod skulle kunna implementeras om en C#-kompilator inte kunde använda operatorerna T.==(T, T) och T.!=(T, T) för Nullable(Of) T) argument.
  • PersonStruct.Equals(PersonStruct?) – implementeringen av gränssnittet IEquatable(Of PersonStruct?) som används för att undvika att linda in Nullable(Of PersonStruct)-argumenten i objekt och anropa metoden PersonStruct.Equals(Object). Det är implementerat som ett anrop av operatören PersonStruct.==(PersonStruct, PersonStruct) med den kommenterade koden för att använda operatorerna T.==(T, T) och T.!=(T, T) för Nullable(Of T) ) argument.
  • PersonStruct.Equals(Object) – som åsidosätter Object.Equals(Object)-metoden. Det implementeras genom att kontrollera kompatibiliteten för en argumenttyp med en typ av det aktuella objektet med hjälp av operatorn is genom att casta argumentet till PersonStruct och anropa PersonStruct.Equals(PersonStruct, PersonStruct).

Anmärkningar:

  • Implementeringen av gränssnittet IEquatable(Of PersonStruct?) — IEquatable(Of Nullable(Of PersonStruct)) tjänar till att visa särskilda problem i plattformen när man arbetar med strukturer där inpackning av instanser till objekt sker snabbare än vi förväntar oss.
  • I verkliga projekt, förutsatt att det inte är nödvändigt att förbättra prestanda, är implementeringen av IEquatable(Of Nullable(Of T)) inte tillämplig av arkitekturskäl – vi bör inte implementera typad IEquatable i T-typen för någon typ.
  • I allmänhet är det inte nödvändigt att överväldiga en kod med olika optimeringar.

För strukturer skulle vi kunna göra jämförelsen efter värde mycket enklare och mer produktiv genom att undvika nedärvning av användardefinierade strukturer och behov av att kontrollera objekt på null. Dessutom kan vi övervaka en ny logik som stöder Nullable(Of T)-argument.

I min framtida publikation kommer jag att sammanfatta följande punkter:

  • När det är en bra idé att genomföra jämförelse av objekt efter värde;
  • Hur vi kan förenkla implementeringen av jämförelse efter värde för objekt – klassinstanser som representerar referenstyper.

Läs även:

Jämföra objekt efter värde. Del 1:Början

Jämföra objekt efter värde. Del 2:Implementationsnoteringar av Equals-metoden

Jämföra objekt efter värde. Del 3:Typspecifika Equals and Equality Operators

Jämföra objekt efter värde. Del 4:Arvs- och jämförelseoperatörer

Jämföra objekt efter värde. Del 5:Strukturjämställdhetsfråga


  1. Hur Acosh() fungerar i PostgreSQL

  2. Postgres lösenordsautentisering misslyckas

  3. Oracle Dynamic SQL-exempel för att infoga en post med DBMS_SQL

  4. SQL-kolumnnamn samma som PL/SQL-variabelnamn - Hur kan detta göras i en select-sats?