Llegado a este punto, vamos a hacer un pequeño parón dentro
de los operadores de consulta, para centrarnos en una interface muy útil dentro de la comparación de nuestros
objetos, y que bajo mi opinión, mucha gente no le da la importancia que
realmente tiene, hasta llegar al punto de que muchos autores ni siquiera le
dediquen una línea dentro de libros dedicados por entero a LinQ.
En
pocas palabras, la interface IEqualityComparer<T>,
nos permite especificar nuestra propia clave de comparación, sin que para ello
tengamos que redefinir ninguno de los métodos iniciales de la clase Object. Esto nos ofrece una
versatilidad gigante, ya que podemos crear todos los que queramos según
nuestras necesidades y nuestro modo de operar. Veremos que esto será clave en
el uso de operadores como Group By,
Distinct, Union, Intersect,
etc.
Recuerda que aquí tienes el indice de todos los posts del Curso de LinQ.
Es importante no confundir con la finalidad de la interfaz IComparer<T>, ya que esta
proporciona funcionalidad de comparación pero para niveles de clasificación y
ordenación.
Para su uso, Microsoft recomienda derivar de la clase EqualityComparer<T> antes de
implementar la Interfaz IEqualityComparer<T>,
pero no creo que haya mucha diferencia entre el uso de uno y otro, ya que la
primera es una clase abstracta
con 2 métodos abstractos (que te obliga a redefinir) y la segunda es una
interfaz con esos dos mismos métodos, que te obligan a implementar.
Como ejemplo pondré las dos firmas la de la clase y la de la
Interface:
Vamos a centrar en explicar los dos métodos que nos
interesan:
Equals à
Acción que determina cuando dos objetos son iguales.
GetHashCode à
Devuelve un código Hash
para el objeto especificado.
Estos son los métodos que tendremos que redefinir o implementar
para crear nuestro comparador personalizado.
Vamos a crear un par de ejemplos para nuestra clase Persona .Antes de nada volvemos a
presentarla por si alguno no se la sabe todavía:
Como hemos dicho en la parte inicial, nuestro objetivo es
crear una clave de comparación, que facilitaremos a nuestros métodos para
indicarle según nuestro criterio, cuando dos objetos del tipo Persona son iguales.
En nuestro
primer ejemplo lo haremos simplemente por el campo Id, que sería el más lógico para este tipo de datos.
Simplemente hemos creado una clase que hereda de EqualityComparer<Persona> y
hemos redefinido sus dos métodos. El método Equals,
que recibe 2 parámetros de tipo Persona, que no son más que los 2 objetos que
compararemos para saber si son o no son iguales. Y el método GetHashCode, en el que reutilizaremos
el mismo método de la clase base Object,
de la propiedad utilizada en cuestión.
Así podremos decirle a cualquier método de comparación o
creación, que para su uso, nosotros entendemos que una persona es igual a otra
si tiene el mismo Id.
Vamos a crear un segundo ejemplo, en el que por necesidades
del guion nos tuviéramos que olvidar de los Ids,
y para nosotros una persona fuera diferente de otra, siempre que no se llamen
igual y hayan nacido en un día diferente.
Vamos a ver el ejemplo:
Así podríamos tener n formas diferentes para diferenciar los
objetos Persona, según
nuestras necesidades.
Cabe destacar que este tipo de acciones lo realizaremos
sobre objetos ‘compuestos’ con un
conjuntos de propiedades. Para estructuras
como int, decimal, datetime, etc., esto no será necesario, ya que por defecto
comparará por su valor. El mismo comportamiento tendrá para sus equivalentes nulables y la clase inmutable string.
Hemos explicado la forma generarla y no hemos hecho ninguna
demostración práctica de cómo aplicarlo en la vida real. Aunque parezca un poco
vacío, en las siguientes entregas, estudiaremos muchos operadores que dentro de
sus sobrecargas admiten una clase de este tipo y que nos harán apreciar su
verdadero valor dentro de LinQ.
No hay comentarios :
Publicar un comentario