jueves, 5 de mayo de 2011

Implementación la funcion compareTo de IComparable en C#






La interfaces IComparable e IComparable<t> de C#, se utilizan para comparar objetos, normalmente del mismo tipo y determinar, si alguno es mayor, menor o la equivalencia. A continuacion, se presentan 4 ejemplos de como implementar esta funcionalidad.

Nota1: Para el primer ejemplo, se utiliza el concepto de National Identification Number (CURP en México, RUN en Chile, DNI en España y Argentina o Tarjeta de Identidad en colombia, por ejemplo)
Nota2: Por razones de compatibilidad, se implementan 2 interfaces distintas, con funcionalidades similares, en la implementacion de estas clases.

class Person1 : System.IComparable, System.IComparable<Person1>
    {
        private string nin; // National Identification Number
        private string name;
        private string surname;

        //...

        public int CompareTo(object obj)
        {
            if (obj is Person1)
            {
                return obj == null ? 1 : nin.CompareTo(((Person1)obj).nin);
            }
            throw new System.ArgumentException();
        }

        public int CompareTo(Person1 p)
        {
            return p == null ? 1 : nin.CompareTo(p.nin);
        }

    }

    class Person2 : System.IComparable, System.IComparable<Person2>
    {
        private int id;
        private string name;
        private string surname;

        //...

        public int CompareTo(object obj)
        {
            if (obj is Person2)
            {
                return obj == null ? 1 : id.CompareTo(((Person2)obj).id);
            }
            throw new System.ArgumentException();
        }

        public int CompareTo(Person2 p)
        {
            return p == null ? 1 : id.CompareTo(p.id);
        }


    }

    class Person3 : System.IComparable, System.IComparable<Person3>
    {
        private int id;
        private string name;
        private string surname;

        //...

        public int CompareTo(object obj)
        {
            if (obj == null)
            {
                return 1;
            }
            else
            {
                if (obj is Person3)
                {
                    Person3 o = (Person3)obj;
                    return id - o.id;
                }
                throw new System.ArgumentException();
            }
        }

        public int CompareTo(Person3 p)
        {
            return p == null ? 1 : id - p.id;
        }

    }

    class Person4 : System.IComparable, System.IComparable<Person4>
    {
        private int idPart1;
        private string idPart2;
        private string name;
        private string surname;

        //...

        private int CompareTo0(Person4 p)
        {
            int v = idPart1 - p.idPart1;
            if (v == 0)
            {
                v = idPart2.CompareTo(p.idPart2);
            }
            return v;
        }

        public int CompareTo(object obj)
        {
            if (obj == null)
            {
                return 1;
            }
            else
            {
                if (obj is Person4)
                {
                    return CompareTo0((Person4)obj);
                }
                throw new System.ArgumentException();
            }
        }

        public int CompareTo(Person4 p)
        {
            if (p == null)
            {
                return 1;
            }
            else
            {
                return CompareTo0(p);
            }
        }

    }


En el primer y segundo ejemplo, se implementa la funcionalidad, utilizando la funcion CompareTo implementada por la clase string y por la estructura int32. Regresando el resultado de ejecutar dicha funcion. En el tercer ejemplo, se muestra, como se puede implementar utilizando la diferencia entre 2 enteros (es posible utilizar cualquier tipo entero, como un byte, short, int). Finalmente, en el cuarto ejemplo, se implementa la funcionalidad utilizando 2 propiedades, donde se compara la primer propiedad y en caso de igualdad, se regresa el resultado de comparar la segunda propiedad. Tambiem, en este ultimo ejemplo, define una funcion intermedia (CompareTo0), la cual hace la comparacion real y es llamada por las 2 implementaciones del CompareTo.

Como se observa. por razones de compatibilidad, es necesario implementar la funcionalidad de 2 interfaces, una utlizando Generics y otra sin pre-generics. En la version Generics, es necesario validar que el tipo de corresponde con la clase que implementa, en caso de no coincidir, hay que generar una excepcion del tipo ArgumentException. En el caso del null, la documentacion tambien especifica regresar 1 explicitamente. Final mente, en C#, como en C, se especifican valores validos cualquier entero positivo, negativo o cero (dentro de los rangos de int32)

Es recomendable, por cuestiones de simplicidad en la implementacion, incluir en la comparacion solo los valores que corresponden a la llave primaria, comparandolos, en orden de importancia, regresando el valor, del primero que resulte distinto (como se muestra en el ejemplo 4).