sql >> Base de Datos >  >> RDS >> Database

Comparación de objetos por valor. Parte 6:Implementación de la igualdad de estructura

Ya hemos analizado las peculiaridades de las estructuras del marco .NET que representan tipos de valor al comparar objetos por valor:instancia de estructuras.

Ahora, voy a describir este proceso en un ejemplo particular para verificar si nos permitirá determinar el uso de la comparación de objetos por valor en general y, por lo tanto, simplificar una muestra de comparación de objetos por valor:instancias de clase que representan referencia. tipos.

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

Como puede ver, este ejemplo es más pequeño y más fácil por estructura, ya que las instancias de estructuras no son nulas y no es posible heredar estructuras definidas por el usuario. Ya hemos discutido las peculiaridades para implementar la comparación por valor para las instancias de clase en mi artículo anterior.

Además, hemos determinado campos para la comparación de objetos e implementado el método GetHashCode().

Los métodos y operadores de comparación se han implementado en el siguiente orden:

  1. Para comparar dos instancias de estructuras, hemos implementado el método estático PersonStruct.Equals(PersonStruct, PersonStruct). Usaremos este método como método de comparación de referencia al implementar otros métodos y operadores. Además, se puede aplicar para comparar instancias de estructuras en idiomas que no admiten operadores.
  2. También se han implementado los operadores PersonStruct.==(PersonStruct, PersonStruct) y PersonStruct.!=(PersonStruct, PersonStruct). Cabe señalar que un compilador de C# tiene las siguientes peculiaridades:
  • Puede comparar con los operadores sobrecargados T.==(T, T) y T.!=(T, T) en Nullable(Of T)
  • Antes de verificar la igualdad de un valor, un compilador puede verificar si las instancias de las estructuras tienen un valor válido. Además, un compilador no envuelve instancias de estructuras en objetos.
  • Por lo tanto, comparar instancias de la estructura Nullable(Of T) con un valor anulable sin tipo lleva a llamar a los operadores ==(T, T) o T.!=(T, T), mientras se comparan instancias de Nullable( De la estructura T) sin operadores sobrecargados T.==(T, T) y T.!=(T, T) da como resultado llamar a los operadores Object.==(Object, Object) u Object.!=(Object, Object) y, como resultado, al envolver una instancia en el objeto.
  1. El método PersonStruct.Equals(PersonStruct) (implementación de IEquatable(Of PersonStruct)) se implementó llamando al método PersonStruct.Equals(PersonStruct, PersonStruct).
  2. Para evitar envolver instancias de estructuras en objetos, cuando tenemos una o dos instancias Nullable(Of PersonStruct), es posible implementar los siguientes métodos:
  • PersonStruct.Equals(PersonStruct?, PersonStruct?), como una llamada del operador PersonStruct.==(PersonStruct, PersonStruct), se usa para evitar envolver instancias de estructuras de ambos argumentos en objetos y llamar a Object.Equals( Object, Object) si al menos uno de los argumentos es una instancia anulable (Of PersonStruct). Además, puede usar este método para comparar instancias anulables (Of PersonStruct) en idiomas que no admiten operadores. En el código, puede encontrar comentarios que explican cómo se podría implementar este método si un compilador de C# no pudiera usar los operadores T.==(T, T) y T.!=(T, T) para Nullable(Of T) argumentos.
  • PersonStruct.Equals(PersonStruct?):la implementación de la interfaz IEquatable(Of PersonStruct?) utilizada para evitar envolver los argumentos Nullable(Of PersonStruct) en objetos y llamar al método PersonStruct.Equals(Object). Se implementa como una llamada del operador PersonStruct.==(PersonStruct, PersonStruct) con el código comentado para usar los operadores T.==(T, T) y T.!=(T, T) para Nullable(Of T ) argumentos.
  • PersonStruct.Equals(Object) – que anula el método Object.Equals(Object). Se implementa comprobando la compatibilidad de un tipo de argumento con un tipo del objeto actual mediante el operador is al convertir el argumento en PersonStruct y llamar a PersonStruct.Equals(PersonStruct, PersonStruct).

Notas:

  • La implementación de la interfaz IEquatable(Of PersonStruct?) — IEquatable(Of Nullable(Of PersonStruct)) sirve para mostrar problemas particulares en la plataforma cuando se trabaja con estructuras donde envolver instancias en objetos ocurre más rápido de lo esperado.
  • En proyectos reales, siempre que no sea necesario mejorar el rendimiento, la implementación de IEquatable(Of Nullable(Of T)) no es aplicable por motivos de arquitectura; no debemos implementar IEquatable tipado en el tipo T para ningún tipo.
  • En general, no es necesario abrumar un código con diferentes optimizaciones.

Para las estructuras, podríamos lograr que la comparación por valor sea mucho más simple y productiva al evitar la herencia de estructuras definidas por el usuario y la necesidad de verificar objetos en nulo. Además, podemos monitorear una nueva lógica que admite argumentos anulables (Of T).

En mi futura publicación, resumiré los siguientes puntos:

  • Cuando es una buena idea implementar la comparación de objetos por valor;
  • Cómo podemos simplificar la implementación de la comparación por valor para objetos:instancias de clase que representan tipos de referencia.

Lea también:

Comparación de objetos por valor. Parte 1:Comienzo

Comparación de objetos por valor. Parte 2:Notas de implementación del método Equals

Comparación de objetos por valor. Parte 3:Operadores de igualdad y de igualdad específicos de tipo

Comparación de objetos por valor. Parte 4:Operadores de herencia y comparación

Comparación de objetos por valor. Parte 5:Cuestión de igualdad de estructura