El blog del burgués

23 junio 2009

Delegados Genéricos

Filed under: C# — elburgues @ 6:11 AM
Tags:

Como las clases, interfaces, estructuras y métodos, los delegados pueden también definir parámetros de tipo genérico. Supón que quieres definir un delegado a través del cual llamar a una función que devuelva void y que reciba un solo parámetro, siendo este parámetro, a priori, de cualquier tipo. Se puede definir esto de la siguiente forma:

  // Este delegado genérico puede llamar a cualquier método
  // que devuelva un void y tome un solo parámetro de cualquier tipo.
  public delegate void MiDelegadoGenerico<T>(T arg);

Es cuando creamos una instancia de un delegado definido de esta forma, cuando tenemos que especificar el tipo de parámetro así como el nombre del método que el delegado invocará.

    // Registro de destinos
    MiDelegadoGenerico<string> strDestino =
     new MiDelegadoGenerico<string>(StringDestino);

    MiDelegadoGenerico<int> intDestino =
     new MiDelegadoGenerico<int>(IntDestino);

 Siendo los “métodos destino” a invocar los siguientes:

    static void StringDestino(string arg)
    {
      Console.WriteLine("arg en mayúsculas es : {0}", arg.ToUpper());
    }

    static void IntDestino(int arg)
    {
      Console.WriteLine("++arg es: {0}", ++arg);
    }

 Los delegados genéricos ofrecen una manera flexible de invocar a un método de forma segura. Antes de la introducción de los genéricos en la release 2.0 de .NET, se podía hacer esto de forma similar:

      // Registrar destino con la sintaxis tradicional de delegados.
      MiDelegado d = new MiDelegado(MyTarget);
      d("Otra cadena.");

      // Registro de destinos utilizando el método de conversión grupo.
      MiDelegado d2 = MiDestino;
      d2(9);  // Penalización en el Boxing.

Siendo MiDestino

    // Al no haber seguridad de tipos, debemos
    // determinar el tipo subyacente antes de la conversión..
    static void MiDestino(object arg)
    {
      if (arg is int)
      {
        int i = (int)arg;  // Penalización por el Unboxing.
        Console.WriteLine("++arg es: {0}", ++i);
      }
      if (arg is string)
      {
        string s = (string)arg;
        Console.WriteLine("arg en mayúsculas es: {0}", s.ToUpper());
      }
    }

El problema que tenía esto es que había que comprobar dinámicamente el tipo subyacente antes de hacer la conversión de tipos, con su correspondiente penalización de Boxing/Unboxing. Esto es lo que dice Microsoft acerca de las penalizaciones por Boxing/Unboxing.

Por último añadir que un delegado puede definir restricciones a sus parámetros genéricos:

public delegate void MiDelegadoGenerico<T>(T arg) where T : IComparable<T>;

El código completo del ejemplo sería este:

using System;
using System.Collections.Generic;
using System.Text;

namespace DelegadosGenericos
{
    // Este delegado genérico puede llamar a cualquier método
    // que devuelva un void y tome un solo parámetro de cualquier tipo.
    public delegate void MiDelegadoGenerico<T>(T arg);

    // Simulando delegados genércios a través de Objects.

    public delegate void MiDelegado(object arg);

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("***** Delegados Genéricos *****\n");
            // Registro de destinos
            MiDelegadoGenerico<string> strDestino =
              new MiDelegadoGenerico<string>(StringDestino);
            strDestino("Alguna cadena.");

            MiDelegadoGenerico<int> intDestino =
              new MiDelegadoGenerico<int>(IntDestino);

            intDestino(9);

            Console.WriteLine("\nAhora sin usar delegados genéricos!\n");

            // Registrar destino con la sintaxis tradicional de delegados.
            MiDelegado d = new MiDelegado(MiDestino);
            d("Otra cadena.");

            // Registro de destinos utilizando el método de conversión grupo.
            MiDelegado d2 = MiDestino;

            d2(9);  // Penalización en el Boxing.
            Console.ReadLine();
        }

        #region Destinos para los delegados genéricos.
        static void StringDestino(string arg)
        {
            Console.WriteLine("arg en mayúsculas es : {0}", arg.ToUpper());
        }

        static void IntDestino(int arg)
        {
            Console.WriteLine("++arg es: {0}", ++arg);
        }

        // Debido a una falta de seguridad de tipos, debemos
        // determinar el tipo subyacente antes de la conversión..
        static void MiDestino(object arg)
        {
            if (arg is int)
            {
                int i = (int)arg;  // Penalización por el Unboxing.
                Console.WriteLine("++arg es: {0}", ++i);
            }
            if (arg is string)
            {
                string s = (string)arg;
                Console.WriteLine("arg en mayúsculas es: {0}", s.ToUpper());
            }
        }
        #endregion
    }
}
Anuncios

Dejar un comentario »

Aún no hay comentarios.

RSS feed for comments on this post. TrackBack URI

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

Crea un blog o un sitio web gratuitos con WordPress.com.

A %d blogueros les gusta esto: