Índice
1. Introducción2. Palabras Clave
3. Operadores < y >
4. Implementación de las Interfaces IComparable
5. Conclusiones
6. Literatura & Enlaces
1. Introducción
En el artículo C# anterior se estudiaron los protocolos estándar de comparación de orden; en especial se habló acerca de las interfaces y operadores de C# que permiten la escritura de tipos de datos cuyos valores siguen un orden establecido. Esta segunda parte describe el contexto donde resulta práctico implementar las interfaces IComparable, y cuándo es viable la sobrecarga de los operadores < y >.
2. Palabras Clave
- Comparación de orden
- IComparable
- IComparable<T>
- Operador >
- Operador <
3. Operadores < y >
Los tipos datos numéricos integrados -byte, int, float, double, decimal, etc.- tienen un orden natural. Este orden establece relaciones como 'menor que', 'mayor que', 'menor o igual que' o 'mayor o igual que'. En el lenguaje de programación C# el programador cuenta con operadores estándar para efectuar operaciones de comparación de orden a través de los operadores <, >, <= y >=.
Esta clase de relaciones no sólo está implementada para valores numéricos sino para otros tipos datos integrados de Microsoft .NET Framework. La estructura DateTime (cfr. Manipulación de Fechas y Horas en C#/5: La Estructura DateTime) sobrecarga las operadores < y > para comparar el orden de fechas.
Ejemplo de uso:
bool despuesDe2019 = DateTime.Now > new DateTime(2019, 1, 1);
Console.WriteLine(despuesDe2019); // False
En este ejemplo el operador > compara la hora fecha actual con 2019/1/1. Se puede pensar que la sobrescritura de > tiene sentido debido a que la representación numérica de una fecha tiene un orden cronológico; inclusive se puede expresar en términos 'viene antes de' o 'viene después de'.
[Nota: El resultado de la evaluación de estas expresiones puede cambiar si este artículo es leído después 2019/1/1.]
Para lograr la comparación del orden de fechas, la estructura DateTime implementa las interfaces IComparable, como se muestra en la Figura 1:
Figura 1. Implementación interfaces IComparable por DateTime ("DateTime Structure", 2016). |
Continuando, en Albahari J. (2012) se anuncia que la sobrecarga de los operadores < y > involucra la implementación de las interfaces IComparable es una práctica estándar; sin embargo, la operación inversa no resulta verdadera. En .NET Framework la gran mayoría de tipos que implementan las interfaces IComparable no sobrecargan los operadores de orden mencionados.
La clase System.String constituye un ejemplo evidente para este último caso:
Figura 2. Comparación errónea en objetos String. |
Aún vale agregar que para la comparación de igualdad, siempre que se sobrecarga el método Equals, es una práctica estándar sobrecargar el operador de igualdad de C# == (Albahari J., 2012).
¿En qué situaciones resulta típico sobrecargar los operadores < y >?:
- El tipo de dato en consideración inherentemente considera los conceptos de 'mayor que' y 'menor que' para los valores que representa.
- El resultado de la evaluación es independiente de la cultura.
- La comparación de orden sólo tiene un único sentido o contexto para llevarse a cabo.
4. Implementación de las Interfaces IComparable
El siguiente ejemplo demuestra cómo implementar los protocolos estándar de comparación de orden discutidos anteriormente. El ejemplo compara semitonos de una nota musical.
Ejemplo de uso:
Archivo C# NotaMusical.cs [Enlace alternativo][Enlace alternativo]:
Líneas sobresalientes de este ejemplo de código fuente C#:
- Líneas 37-46: Implementa el método CompareTo de la interfaz genérica IComparable<NotaMusical>. Dentro de este método se comprueba que si dos objetos del tipo paramétrico son iguales, entonces ambos ocupan el mismo lugar de orden. En caso contrario se efectúa la comparación con la implementación de CompareTo para valores de int de la propiedad miembro de esta estructura.
- Líneas 49-58: Implementa el método CompareTo de la versión no genérica de la interfaz IComparable. Primero se comprueba que si el tipo de dato es de tipo NotaMusical; de no ser así se genera la excepción InvalidOperationException. Luego la comparación se efectúa con la versión genérica de CompareTo (línea 57).
- Líneas 69-78: Se sobrecarga los operadores < y >. Nótese que se usan el método CompareTo y el operador == (más adelante sobrecargado). Esto garantiza la consistencia de comparación de igualdad y comparación de valores.
- Líneas 75-78: Sobrecarga el método Equals de la interfaz genérica IEquatable<NotaMusical>. Aquí también se usa el operador == sobrecargado en esta misma estructura. También se sobrescribe Object.Equals para mantener la consistencia con esta versión genérica.
- Líneas 100-110: Sobrecarga de los operadores == y != para la comparación de igualdad de objetos NotaMusical.
Salida resultante de la ejecución de este código en LINQPad:
nm1 == nm2 : False
nm1.Equals((object)nm2): False
nm1 == nm3 : True
nm1.Equals((object)nm2): True
nm1 < nm2: True
nm1 != nm2: True
nm1.Equals((object)nm2): False
nm1 == nm3 : True
nm1.Equals((object)nm2): True
nm1 < nm2: True
nm1 != nm2: True
5. Conclusiones
Se demostró a través de un ejemplo cómo el programador puede implementar las interfaces IComparable (no-genérica y genérica) y IEquatable<T> para definir una semántica natural tanto de comparación de igualdad y de orden para el tipo de dato NotaMusical. El poder que entrega este conocimiento al programador consiste en crear tipo de datos robustos y acordes a un dominio real.
Este capítulo de artículos C# -Capítulo 6: Fundamentos de .NET Framework- terminará con la exposición de las clases de utilidad disponibles en C#.
6. Literatura & Enlaces
Albahari, J., Albahari, B. (2012). C# 5.0 in a Nutshell. United States: O'Reilly Media.Manipulación de Fechas y Horas en C#/5: La Estructura DateTime (2016, julio 31). Recuperado desde: https://ortizol.blogspot.com/2016/06/manipulacion-de-fechas-y-horas-en-csharp-parte-2-5-la-estructura-datetime.html
DateTime Structure (System) (2016, julio 31). Recuperado desde: https://msdn.microsoft.com/en-us/library/system.datetime.aspx
Semitono, la enciclopedia libre (2016, julio 31). Recuperado desde: https://es.wikipedia.org/wiki/Semitono
O