Un delegado es un tipo que representa una referencia a una función o método. Los delegados permiten que los métodos se pasen como parámetros, se asignen a variables y se ejecuten dinámicamente en tiempo de ejecución.
Para ello, el delegado debe coincidir con la firma (parámetros recibidos) por la función, y con su retorno específico.
En términos simples, un delegado puede considerarse como una especie de puntero a función, pero con la seguridad y la robustez del sistema de tipos de C#.
Si quieres aprender más sobre Referencia a Funciones
consulta el Curso de Introducción a la Programación leer más
Declaración de un delegado
Para declarar un delegado en C# se utiliza la palabra clave delegate
, seguida de la firma del método que el delegado representará.
delegate TipoRetorno MiDelegado(Tipo parametro1...);
- TipoRetorno, el tipo de retorno de la función que queremos delegar
- Tipo parametro…, los parámetros de la función que queremos delegar
Por ejemplo, si queremos declarar un delegado que represente un método que no devuelve ningún valor y toma dos parámetros enteros, la declaración se vería así:
Ejemplo básico
Por ejemplo, si quisiéramos definir un delegado que pueda apuntar a cualquier función que tome un string
como parámetro y no retorne ningún valor (void
), podríamos hacerlo así:
public delegate void MiDelegado(string mensaje);
Y si queremos declarar un delegado que referencia una función que tome dos parámetros int
y devuelva un double
la declaración se vería así:
delegate void MiDelegado(int parametro1, int parametro2);
Uso de delegados
Asignación de un método a un delegado
Una vez declarado el delegado, podemos crear una instancia del delegado y asignarle un método que coincida con su firma.
Para ello podemos crearlo usando su constructor
MiDelegado delegado = new MiDelegado(FuncionReferenciada);
O simplemente asignarlo
MiDelegado delegado = FuncionReferenciada;
Veámoslo con un ejemplo. Supongamos que tenemos la función MostrarMensaje(string ...)
.
// Método que queremos referenciar
public static void MostrarMensaje(string mensaje)
{
Console.WriteLine("Delegado:" + mensaje);
}
// Definición del delegado
public delegate void MiDelegado(string mensaje);
public static void Main(string[] args)
{
// Ahora creamos un MiDelegado que apunte a MostrarMensaje
MiDelegado delegado = MostrarMensaje;
}
Aquí hemos,
- Definido un delegado
MiDelegado
, que coincide con la forma deMostrarMensaje
. - Creado una nueva instancia de
MiDelegado
, llamadadelegado
- Asignado la instancia
delegado
aMostrarMensaje
.
Invocando un delegado
Una vez que hemos creado definido el delegado, credo un delegado, y referenciada una función con él, podemos invocarlo simplemente haciendo ()
como haríamos con la función original.
En el ejemplo anterior, podríamos invocar delegado
simplemente así.
// Invocación del método a través del delegado
delegado("Hola, Mundo!");
}
Por lo que se mostraría en pantalla
Delegado: Hola, Mundo!
Delegados genéricos: Func
y Action
Para simplificar el uso de delegados, C# dispone de delegados genéricos predefinidos.
Los más comunes son Action
y Func
.
Action
: Representa un método que no retorna un valorFunc<TResult>
: Representa un método que retorna un valor de tipoTResult
Uso de Action
Action<string> mostrar = mensaje => Console.WriteLine(mensaje);
mostrar("Hola con Action!");
Uso de Func
Func<int, int, int> sumar = (a, b) => a + b;
int resultado = sumar(3, 4);
Console.WriteLine("Resultado de la suma: " + resultado);
En general, esta forma es la que usaréis normalmente, frente a definir el delegado explícitamente. Sobre todo si es un uso temporal, que no merece la pena definir de forma tradicional.
Delegados Multicast
Un delegado Multicast es un delegado que puede tener más de un método en su invocación. En realidad, todos los delegados de C# son Multicast
Lo vemos en esta entrada leer más
Uso de delegados con eventos
Los delegados son la base de los eventos en C#. Un evento es una notificación enviada por un objeto para señalar la ocurrencia de una acción. Los delegados permiten suscribir métodos que serán llamados cuando se dispara el evento.
Lo vemos en esta entrada leer más
Ejemplos prácticos
Delegado que no devuelve nada
Aquí tenemos un ejemplo de un delegado que no devuelve nada (void
).
// Declaración del delegado que no devuelve nada
public delegate void MostrarMensajeDelegate(string mensaje);
// Método que coincide con la firma del delegado
public static void MostrarMensaje(string mensaje)
{
Console.WriteLine(mensaje); // Imprimir el mensaje
}
// Uso
MostrarMensajeDelegate mostrarMensaje = MostrarMensaje; // Asignar el método al delegado
mostrarMensaje("Hola, Mundo!"); // Invocar el delegado
Delegado que devuelve un valor
Aquí hay un ejemplo de un delegado que devuelve un valor. En el ejemplo, el delegado toma dos enteros como parámetros y devuelve un entero.
// Declaración del delegado que devuelve un valor
public delegate int SumarDelegate(int a, int b);
// Método que coincide con la firma del delegado
public static int Sumar(int a, int b)
{
return a + b; // Retornar la suma de los dos números
}
// Uso
SumarDelegate sumar = Sumar; // Asignar el método al delegado
int resultado = sumar(3, 5); // Invocar el delegado y obtener el resultado
Console.WriteLine($"Resultado de la suma: {resultado}"); // Imprimir el resultado
Delegado genérico Action
Veamos un ejemplo que usa un delegado genérico Action<T>
para representar un método que no devuelve un valor y que puede tomar parámetros.
// Método que coincide con la firma de Action
public static void ImprimirMensaje(string mensaje)
{
Console.WriteLine(mensaje); // Imprimir el mensaje
}
// Uso
Action<string> imprimir = ImprimirMensaje; // Asignar el método al delegado Action
imprimir("Este es un mensaje usando Action."); // Invocar el delegado
Delegado Genérico Func
Ahora un ejemplo de delegado genérico Func<T
que puede representar un método que devuelve un valor y que puede tomar parámetros.
// Método que coincide con la firma de Func
public static double CalcularAreaCirculo(double radio)
{
return Math.PI * radio * radio; // Calcular y retornar el área del círculo
}
// Uso
Func<double, double> calcularArea = CalcularAreaCirculo; // Asignar el método al delegado Func
double area = calcularArea(5.0); // Invocar el delegado y obtener el resultado
Console.WriteLine($"Área del círculo: {area}"); // Imprimir el área del círculo
Delegado como parámetro en un Método
En este ejemplo veremos como pasar un delegado como parámetro a otro método,
// Declaración del delegado que no devuelve nada
public delegate void OperacionDelegate(int x, int y);
// Método que usa un delegado como parámetro
public static void RealizarOperacion(int a, int b, OperacionDelegate operacion)
{
operacion(a, b); // Invocar el delegado
}
// Métodos que coinciden con la firma del delegado
public static void Sumar(int a, int b)
{
Console.WriteLine($"Suma: {a + b}");
}
public static void Multiplicar(int a, int b)
{
Console.WriteLine($"Producto: {a * b}");
}
// Uso
OperacionDelegate operacionSuma = Sumar; // Asignar el método Sumar al delegado
OperacionDelegate operacionMultiplicacion = Multiplicar; // Asignar el método Multiplicar al delegado
RealizarOperacion(3, 4, operacionSuma); // Pasar el delegado al método
RealizarOperacion(3, 4, operacionMultiplicacion); // Pasar el delegado al método