sql >> Database >  >> RDS >> Database

Objecten vergelijken op waarde. Deel 6:Implementatie van structuurgelijkheid

We hebben al eigenaardigheden geanalyseerd van structs van het .NET-framework die waardetypen vertegenwoordigen bij het vergelijken van objecten op waarde - instantie van structs.

Nu ga ik dit proces beschrijven aan de hand van een bepaald voorbeeld om te controleren of het ons in staat zal stellen om het gebruik van de objectvergelijking op waarde in het algemeen te bepalen en zo een voorbeeld van het vergelijken van objecten op waarde te vereenvoudigen - klasse-instanties die referentie vertegenwoordigen soorten.

De PersonStruct-structuur:

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

Zoals u kunt zien, is dit voorbeeld kleiner en eenvoudiger qua structuur, omdat instanties van structs niet null zijn en het niet mogelijk is om te erven van door de gebruiker gedefinieerde structs. We hebben in mijn vorige artikel al eigenaardigheden besproken om de vergelijking op waarde voor de klasseninstanties te implementeren.

Daarnaast hebben we velden voor objectvergelijking bepaald en de GetHashCode()-methode geïmplementeerd.

Methoden en operatoren voor vergelijking zijn geïmplementeerd in de volgende volgorde:

  1. Om twee instanties van structs te vergelijken, hebben we de statische methode PersonStruct.Equals(PersonStruct, PersonStruct) geïmplementeerd. We zullen deze methode gebruiken als referentievergelijkingsmethode bij het implementeren van andere methoden en operators. Bovendien kan het worden toegepast om instanties van structs te vergelijken in talen die geen operators ondersteunen.
  2. De operators PersonStruct.==(PersonStruct, PersonStruct) en PersonStruct.!=(PersonStruct, PersonStruct) zijn ook geïmplementeerd. Opgemerkt moet worden dat een C#-compiler de volgende eigenaardigheden heeft:
  • Je kunt vergelijken met de overbelaste operatoren T.==(T, T) en T.!=(T, T) in de Nullable(Of T)
  • Alvorens een waardegelijkheid te controleren, kan een compiler controleren of instanties van structs een geldige waarde hebben. Bovendien verpakt een compiler instanties van structs niet in objecten.
  • Het vergelijken van instanties van de Nullable(Of T)-structuur met een niet-getypeerde nullable-waarde leidt dus tot het aanroepen van de ==(T, T) of T.!=(T, T)-operatoren, terwijl instanties van de Nullable( Of T) structuur zonder overbelaste operatoren T.==(T, T) en T.!=(T, T) resulteert in het aanroepen van de Object.==(Object, Object) of Object.!=(Object, Object) operatoren en, als resultaat, het inpakken van een instantie in het object.
  1. De PersonStruct.Equals(PersonStruct) methode (implementatie van IEquatable(Of PersonStruct)) is geïmplementeerd door de PersonStruct.Equals(PersonStruct, PersonStruct) methode aan te roepen.
  2. Om te voorkomen dat instanties van structs in objecten worden verpakt, is het mogelijk om de volgende methoden te implementeren wanneer we een of twee Nullable(Of PersonStruct)-instanties hebben:
  • PersonStruct.Equals(PersonStruct?, PersonStruct?), als aanroep van de PersonStruct.==(PersonStruct, PersonStruct) operator, wordt gebruikt om te voorkomen dat instanties van structs van beide argumenten in objecten worden verpakt en de Object.Equals( Object, Object) als ten minste één van de argumenten een instantie Nullable(Of PersonStruct) is. Bovendien kunt u deze methode gebruiken om Nullable (Of PersonStruct)-instanties te vergelijken in talen die geen operators ondersteunen. In de code vindt u mogelijk opmerkingen waarin wordt uitgelegd hoe deze methode zou kunnen worden geïmplementeerd als een C#-compiler de operatoren T.==(T, T) en T.!=(T, T) niet kon gebruiken voor de Nullable(Of T) argumenten.
  • PersonStruct.Equals(PersonStruct?) – de implementatie van de IEquatable(Of PersonStruct?) interface die wordt gebruikt om te voorkomen dat de Nullable(Of PersonStruct)-argumenten in objecten worden verpakt en de PersonStruct.Equals(Object)-methode wordt aangeroepen. Het wordt geïmplementeerd als een aanroep van de PersonStruct.==(PersonStruct, PersonStruct) operator met de becommentarieerde code om T.==(T, T) en T.!=(T, T) operatoren te gebruiken voor de Nullable(Of T) ) argumenten.
  • PersonStruct.Equals(Object) – die de methode Object.Equals(Object) overschrijft. Het wordt geïmplementeerd door de compatibiliteit van een argumenttype met een type van het huidige object te controleren met behulp van de is-operator door het argument naar PersonStruct te casten en PersonStruct.Equals (PersonStruct, PersonStruct) aan te roepen.

Opmerkingen:

  • De implementatie van de IEquatable(Of PersonStruct?) — IEquatable(Of Nullable(Of PersonStruct))-interface dient om bepaalde problemen in het platform te tonen bij het werken met structs waarbij het inpakken van instanties in objecten sneller gebeurt dan we verwachten.
  • In echte projecten, op voorwaarde dat het niet nodig is om de prestaties te verbeteren, is de implementatie van IEquatable(Of Nullable(Of T)) niet van toepassing om architectuurredenen - we zouden voor geen enkel type getypte IEquatable in het T-type moeten implementeren.
  • Over het algemeen is het niet nodig om een ​​code te overstelpen met verschillende optimalisaties.

Voor structuren zouden we kunnen bereiken om de vergelijking op waarde veel eenvoudiger en productiever te maken door overerving van door de gebruiker gedefinieerde structs te vermijden en objecten op null te controleren. Bovendien kunnen we een nieuwe logica volgen die Nullable (Of T) -argumenten ondersteunt.

In mijn toekomstige publicatie zal ik de volgende punten samenvatten:

  • Als het een goed idee is om een ​​vergelijking van objecten op waarde te implementeren;
  • Hoe we de implementatie van vergelijking op waarde voor objecten kunnen vereenvoudigen - klasseninstanties die referentietypen vertegenwoordigen.

Lees ook:

Objecten vergelijken op waarde. Deel 1:Begin

Objecten vergelijken op waarde. Deel 2:Implementatienota's van de Equals-methode

Objecten vergelijken op waarde. Deel 3:Typespecifieke operatoren voor gelijken en gelijkheid

Objecten vergelijken op waarde. Deel 4:Overervings- en vergelijkingsoperators

Objecten vergelijken op waarde. Deel 5:Probleem met structuurgelijkheid


  1. Kan het sorteerconflict tussen SQL_Latin1_General_CP1_CI_AS en Latin1_General_CI_AS niet oplossen in de gelijk aan-bewerking

  2. Geclusterde en niet-geclusterde index:7 toppunten uitgelegd

  3. UTC_DATE Voorbeelden - MySQL

  4. Tekst of numeriek veld - Een eenvoudige SQL-methode om van gegevenstype te wisselen