Autor Tema: [C#] Funciones anónimas y delegados  (Leído 1950 veces)

JaviCepa

  • Socio
  • Mega Jammer
  • ****
  • Mensajes: 433
  • Molas: 45
    • @JaviCepa
[C#] Funciones anónimas y delegados
« en: 14 de Agosto de 2015, 05:00:25 pm »
Voy al grano, una explicación rápida y poco precisa de lo que son los delegados:
Los delegados son variables en las que guardas funciones en vez de datos

Por ejemplo, yo soy un delegado en el que mi pareja guarda la función "saca la basura". Cuando llega el momento adecuado, yo ejecuto esas funciones que tengo guardadas dentro de mí.

Para poder guardar las funciones, primero tenemos que explicarle al programa que tipo de entradas y salidas tienen las funciones que se van a guardar. Algunos delegados comunes:
  • System.Action este es muy fácil, ningún argumento de entrada y ninguna salida (o salida "void")
  • System.Predicate uno o ningún argumento de entrada de cualquier tipo, y un argumento de salida de tipo "bool"
  • System.Func cualquier número de argumentos de entrada y uno de salida (los tipos se especifican mediante genéricos)

Además en una variable-delegado, al contrario que como pasa con las variables de dato, podemos guardar varias funciones. Por ejemplo podemos hacer cosas así:
Código: [Seleccionar]
void ComprarPatatas() {
    Debug.Log("Patatas compradas");
}
void ComprarHuevos() {
    Debug.Log("Huevos comprados");
}
void ComprarPan() {
    Debug.Log("Pan comprado");
}

void Start() {
    System.Action TareasDeCompra;
    TareasDeCompra+=ComprarPatatas; //Añadimos una "tarea", importante no poner los paréntesis, ya que me refiero a la tarea, no al resultado de hacer esa tarea
    TareasDeCompra+=ComprarHuevos; //Añadimos otra "tarea"
    TareasDeCompra+=ComprarPan; //Añadimos una "tarea"
    TareasDeCompra(); //Invocamos todas las funciones del delegado en el orden en el que se agregaron
}

//Esto devolvería en la consola:
//Patatas compradas
//Huevos comprados
//Pan comprado

Las aplicaciones son muchísimas, podéis utilizar el hilo para comentarlas.

La segunda parte del post trata de otro tema interesante a cola de este: funciones lambda o anónimas.

Las funciones lambda sirven para definir funciones de una forma breve y sin nombre. Como no tienen nombre, las tenemos que guardar en algún sitio para poder invocarlas, en un delegado.
Explico la notación con un ejemplo sencillo. Una función como la siguiente:
Código: [Seleccionar]
//Ejemplo súper original:
void Sum(int a, int b) {
    return a+b;
}
Se podría escribir con la siguiente expresión lambda:
Código: [Seleccionar]
(int a, int b)=>a+b
O incluso más abreviado:
Código: [Seleccionar]
(a, b)=>a+b

Una forma fácil de leer estas funciones es "lo de la izquierda me devuelve lo de la derecha" o también "(inputs)=>output"

Volviendo con los delegados, ahora podríamos repetir el ejemplo de arriba de una forma mucho más breve, sin declarar las funciones:
Código: [Seleccionar]
void Start() {
    System.Action TareasDeCompra;
    TareasDeCompra+= ()=>Debug.Log("Patatas compradas");
    TareasDeCompra+= ()=>Debug.Log("Huevos comprados");
    TareasDeCompra+= ()=>Debug.Log("Pan comprado");
    TareasDeCompra();
}

//Esto devolvería en la consola:
//Patatas compradas
//Huevos comprados
//Pan comprado

Espero que os sea útil! Sirven para un montón de cosas.

JuDelCo

  • En evolución
  • Socio
  • Super Jammer
  • ***
  • Mensajes: 240
  • Molas: 35
  • The Game
    • Twitter
Re:[C#] Funciones anónimas y delegados
« Respuesta #1 en: 14 de Agosto de 2015, 05:34:45 pm »
Las funciones anónimas (lambdas) se pueden definir también entre corchetes (de otra forma son consideradas más bien "expresiones").

De forma que el ejemplo propuesto:

Código: [Seleccionar]
(int a, int b)=>a+b;

Se puede definir como

Código: [Seleccionar]
(int a, int b) => { return a+b; };

¿ y para qué me preguntaréis? Pues bien, esto permite añadir dos o más lineas de código a las funciones anónimas, no simples expresiones ;) (Pero no os olvideis el return y el punto y coma del final detrás del corchete !!

-----------------------------------------------

Corolario: El primer corchete de la expresión debe de estar en la misma línea que la definición del lambda, el resto de elementos podeis hacer lo que queráis. Por lo que:

BIEN:
Código: [Seleccionar]
(int a, int b) => {
      a++;
      return a+b;
};

MAL:
Código: [Seleccionar]
(int a, int b) =>
{
      a++;
      return a+b;
};