jueves, 19 de septiembre de 2013

Genéricos para un amigo

Hoy me pregunto un amigo como pasaba un array a una función que recibe como parámetro un IEnumerable. Así que decido ahorrar mis pulsaciones de teclado y escribir este post como respuesta.
En .net un array se puede asignar a un IEnmerable genérico sin necesidad de hacer cast, así que podemos hacer algo como esto:
        static void Main(string[] args)
        {
            //En .net un array puede ser igualado a un ienumerable sin cast
            string[] nombres = {"Pedro", "Manel", "Chema", "Oscar", "Noe", "Elías"};

            IEnumerable<string> coleccionNombres = nombres;

            foreach (string nombre in coleccionNombres ) {
                Console.WriteLine(nombre);
            }

            Console.ReadLine();

        }

Así que también puede crear un método que reciba un IEnumerable y puede enviar directamente un array
        static void Main(string[] args)
        {
            //En .net un array puede ser igualado a un ienumerable sin cast
            string[] nombres = {"Pedro", "Manel", "Chema", "Oscar", "Noe", "Elías"};

            EscribirStringsPorConsola(nombres);

            Console.ReadLine();

        }

        static void EscribirStringsPorConsola(IEnumerable<string> Strings)
        {
            foreach (string cadena in Strings)
            {
                Console.WriteLine(cadena);
            }
        }

Le pregunté a mi amigo qué estaba haciendo y me dijo que estaba escribiendo un repositorio. Supongamos que  está haciendo una repositorio de Personas. El repositorio quedaría algo parecido a esto.
    public class Persona
    {
        public string Nombre { get; set; }
        public string Apellido { get; set; }

    }

    public class RepositorioPersonas 
    {
        public void Add(Persona persona)
        {
            //Implementar Método ADD para persona
        }

        public void Add(IEnumerable<Persona> personas)
        {
            //Implementar Método ADD para personas
        }
        //Implementar resto de métodos de repositorio
    }

Supongamos ahora que tiene que hacer otro repositorio, por ejemplo un repositorio de ciudades. Buena parte del código sería el mismo. Copiar y pegar el código cambiando el tipo no es la solución. Aquí es donde entra en juego los genéricos.
Mucha gente utiliza las clases genéricas, pero no hay tanta gente que crea sus propios genéricos.
Los genéricos están desde Java 1.5 y desde el framework 2.0 de .net en c# y vb.net. Aunque el comportamiento y sintaxis es muy similar hay pequeñas diferencias en este completísimo post.
Como comentaba antes, copiar y pegar no es la solución, puede que un repositorio genérico lo sea. En el ejemplo a continuación no voy a implementar un repositorio genérico de NHibernate o de EntityFramework, pero son muy fáciles de encontrar varios ejemplos en google o en bing o cualquier otro buscador.
        public class Repositorio<T>
        {
            public void Add(T entidad)
            {
                //Implementar Método ADD para entidad
            }

            public void Add(IEnumerable<T> entidades)
            {
                //Implementar Método ADD para entidades
            }
            //Implementar resto de métodos
        }

        public class Persona
        {
            public string Nombre { get; set; }
            public string Apellido { get; set; }

        }

        public class Ciudad
        {
            public string Nombre { get; set; }

        }

        static void Main(string[] args)
        {
            var RepositorioPersonas = new Repositorio<Persona>();
            var RepositorioCiudades = new Repositorio<Ciudad>();
        }

Si mi amigo estuviese diseñando un api en el que le interesase limitar el tipo de clases que maneja el repositorio, podría poner una restricción al genérico. Por ejemplo usando únicamente clases que heredan de una clase en concreto o implementan un determinado interfaz. Por ejemplo:
        public class Entidad
        {
            public int Id { get; set; }
        }
        public class Repositorio<T> where T:Entidad
        {
            public void Add(T entidad)
            {
                //Implementar Método ADD para entidad
            }

            public void Add(IEnumerable<T> entidades)
            {
                //Implementar Método ADD para entidades
            }
            //Implementar resto de métodos
        }

        public class Persona : Entidad
        {
            public string Nombre { get; set; }
            public string Apellido { get; set; }

        }

        public class Ciudad : Entidad
        {
            public string Nombre { get; set; }

        }

        static void Main(string[] args)
        {
            var RepositorioPersonas = new Repositorio<Persona>();
            var RepositorioCiudades = new Repositorio<Ciudad>();
        }

Espero que este post le haya servido a mi amigo a comprender los genéricos y si a alguien más le sirve, matamos dos pájaros de un tiro

4 comentarios:

  1. Joder tío, te lo ha currado un mazo, muchas gracias! me ha quedado todo clarísimo!

    ResponderEliminar
    Respuestas
    1. Con este entusiasmo da gusto escribir posts ;)

      Eliminar
  2. Aquí cualquiera es amigo... es que de verdad...

    Por cierto, Manel, ahora que eres multidisciplinar podrías hacer unos posts de introducción a Java o algo...

    ResponderEliminar
    Respuestas
    1. Pedro, algun post de hibernate lo hice con Java, pero tranquilo, quizás haga algun post sobre alguna nueva característica de Java 8
      Pero bueno, Java es más trabajo y .net es más ocio :P

      Eliminar