Comprender la delegación en C#
Los delegados en C# son una potente función, pero muchos desarrolladores no están familiarizados con su uso eficaz. El vídeo de Tim Corey sobre "Delegates in C# - A practical demonstration, including Action and Func" ofrece una explicación exhaustiva de qué son los delegados, cómo utilizarlos y por qué son útiles.
Este artículo le proporcionará la visión experta de Tim sobre los delegados en C#, ofreciendo una explicación clara de su uso y aplicaciones prácticas. Aprenderás cómo los delegados pueden mejorar la flexibilidad y eficiencia de tu código, con ejemplos como su uso en un sistema de carrito de la compra.
Introducción
Tim introduce el concepto de delegados, destacando su potencia y versatilidad en C#. Asegura a los espectadores que, a pesar de cierta terminología intimidatoria, la base de los delegados es sencilla. Tim pretende desmitificar los delegados y cubrir tipos especiales como func y action.
Paseo por la aplicación demo
Tim crea una aplicación de demostración para ilustrar el uso de los delegados. La solución contiene tres proyectos: una interfaz de usuario de consola, una biblioteca de demostración y una interfaz de usuario WinForm. Inicialmente, la atención se centrará en la interfaz de usuario de la consola y en la biblioteca de demostraciones.
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleUI
{
class Program
{
static ShoppingCartModel cart = new ShoppingCartModel();
static void Main(string[] args)
{
PopulateCartWithDemoData();
Console.WriteLine($"The total for the cart is {cart.GenerateTotal():C2}");
Console.ReadLine();
}
private static void PopulateCartWithDemoData()
{
cart.Items.Add(new ProductModel { ItemName = "Cereal", Price = 3.63M });
cart.Items.Add(new ProductModel { ItemName = "Milk", Price = 2.95M });
cart.Items.Add(new ProductModel { ItemName = "Strawberries", Price = 7.51M });
cart.Items.Add(new ProductModel { ItemName = "Blueberries", Price = 6.75M });
}
}
}
public class ShoppingCartModel
{
public List<ProductModel> Items { get; set; } = new List<ProductModel>();
public decimal GenerateTotal()
{
decimal subtotal = Items.Sum(x => x.Price);
if (subtotal > 100)
{
return subtotal * 0.80M;
}
else if (subtotal > 50)
{
return subtotal * 0.85M;
}
else if (subtotal > 10)
{
return subtotal * 0.90M;
}
else
{
return subtotal;
}
}
}
public class ProductModel
{
public string ItemName { get; set; }
public decimal Price { get; set; }
}
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleUI
{
class Program
{
static ShoppingCartModel cart = new ShoppingCartModel();
static void Main(string[] args)
{
PopulateCartWithDemoData();
Console.WriteLine($"The total for the cart is {cart.GenerateTotal():C2}");
Console.ReadLine();
}
private static void PopulateCartWithDemoData()
{
cart.Items.Add(new ProductModel { ItemName = "Cereal", Price = 3.63M });
cart.Items.Add(new ProductModel { ItemName = "Milk", Price = 2.95M });
cart.Items.Add(new ProductModel { ItemName = "Strawberries", Price = 7.51M });
cart.Items.Add(new ProductModel { ItemName = "Blueberries", Price = 6.75M });
}
}
}
public class ShoppingCartModel
{
public List<ProductModel> Items { get; set; } = new List<ProductModel>();
public decimal GenerateTotal()
{
decimal subtotal = Items.Sum(x => x.Price);
if (subtotal > 100)
{
return subtotal * 0.80M;
}
else if (subtotal > 50)
{
return subtotal * 0.85M;
}
else if (subtotal > 10)
{
return subtotal * 0.90M;
}
else
{
return subtotal;
}
}
}
public class ProductModel
{
public string ItemName { get; set; }
public decimal Price { get; set; }
}
Tim explica la estructura y funcionalidad de la aplicación de demostración:
-
Modelo de carrito de la compra: Representa el carrito de la compra con una lista de artículos (ProductModel) y calcula el coste total con descuentos basados en el subtotal.
-
Modelo de producto: Representa artículos individuales con propiedades de nombre y precio.
- Aplicación de consola: Rellena el carrito con los datos de la demo, calcula el total y lo muestra.
Entender los descuentos
Tim recorre la lógica del descuento en el método GenerateTotal, explicando cómo el subtotal determina el descuento aplicado:
- 20% de descuento para subtotales superiores a 100 $.
- 15% de descuento para subtotales superiores a 50 $.
- 10% de descuento para subtotales superiores a 10 $.
- Sin descuento para subtotales de 10 $ o menos.
Tim utiliza un punto de interrupción para demostrar la lógica de cálculo y descuento, asegurándose de que los espectadores entienden la base antes de introducir a los delegados.
Explicación y creación de un delegado
En esta sección, Tim Corey se sumerge en el concepto de delegados en C#, explicando cómo funcionan y demostrando su uso con ejemplos prácticos de código.
¿Qué es un delegado?
Tim explica que un delegado es esencialmente una forma de pasar métodos como parámetros. En lugar de pasar una variable o una propiedad, se pasa un método, lo que permite un código más flexible y reutilizable.
Creación y uso de un delegado
A continuación, Tim desglosa el proceso de creación y uso de un delegado:
-
Definir el delegado:
- El delegado se define en la parte superior de la clase, especificando el tipo de retorno y los tipos de parámetros.
public delegate void MentionDiscount(decimal subtotal);public delegate void MentionDiscount(decimal subtotal);- Este delegado especifica un método que devuelve void y toma un decimal como parámetro.
-
Uso del delegado en un método:
- El delegado se utiliza como parámetro en el método GenerateTotal de la clase ShoppingCartModel.
public decimal GenerateTotal(MentionDiscount mentionDiscount) { decimal subtotal = Items.Sum(x => x.Price); // Call a method passed as a delegate mentionDiscount(subtotal); if (subtotal > 100) { return subtotal * 0.80M; } else if (subtotal > 50) { return subtotal * 0.85M; } else if (subtotal > 10) { return subtotal * 0.90M; } else { return subtotal; } }public decimal GenerateTotal(MentionDiscount mentionDiscount) { decimal subtotal = Items.Sum(x => x.Price); // Call a method passed as a delegate mentionDiscount(subtotal); if (subtotal > 100) { return subtotal * 0.80M; } else if (subtotal > 50) { return subtotal * 0.85M; } else if (subtotal > 10) { return subtotal * 0.90M; } else { return subtotal; } } -
Creación de un método para pasarlo al delegado:
- En la clase Program se crea un método que coincide con la firma del delegado.
private static void SubtotalAlert(decimal subtotal) { Console.WriteLine($"The subtotal is {subtotal:C2}"); }private static void SubtotalAlert(decimal subtotal) { Console.WriteLine($"The subtotal is {subtotal:C2}"); } -
Llamada al método GenerateTotal:
- El método se pasa al método GenerateTotal a través del delegado.
class Program { static ShoppingCartModel cart = new ShoppingCartModel(); static void Main(string[] args) { PopulateCartWithDemoData(); Console.WriteLine($"The total for the cart is {cart.GenerateTotal(SubtotalAlert):C2}"); Console.ReadLine(); } private static void PopulateCartWithDemoData() { cart.Items.Add(new ProductModel { ItemName = "Cereal", Price = 3.63M }); cart.Items.Add(new ProductModel { ItemName = "Milk", Price = 2.95M }); cart.Items.Add(new ProductModel { ItemName = "Strawberries", Price = 7.51M }); cart.Items.Add(new ProductModel { ItemName = "Blueberries", Price = 6.75M }); } }class Program { static ShoppingCartModel cart = new ShoppingCartModel(); static void Main(string[] args) { PopulateCartWithDemoData(); Console.WriteLine($"The total for the cart is {cart.GenerateTotal(SubtotalAlert):C2}"); Console.ReadLine(); } private static void PopulateCartWithDemoData() { cart.Items.Add(new ProductModel { ItemName = "Cereal", Price = 3.63M }); cart.Items.Add(new ProductModel { ItemName = "Milk", Price = 2.95M }); cart.Items.Add(new ProductModel { ItemName = "Strawberries", Price = 7.51M }); cart.Items.Add(new ProductModel { ItemName = "Blueberries", Price = 6.75M }); } }
Ejecución de la aplicación
Tim ejecuta la aplicación para demostrar cómo funciona el delegado. La salida de la consola muestra el subtotal y el total del carrito, lo que indica que el método SubtotalAlert se ha pasado y ejecutado correctamente a través del delegado.

Func y Acción: Problemas que puedes resolver con delegados
A continuación, Tim Corey explora el uso de delegados func y action en C#. Se trata de tipos especiales de delegados proporcionados por Microsoft para simplificar el uso de delegados con genéricos.
Identificación del problema
Tim destaca un problema común: la lógica de descuento codificada en el método GenerateTotal. Este enfoque es inflexible y requiere cambios en el código, recompilación y redistribución cada vez que cambian las reglas de descuento.
public decimal GenerateTotal()
{
decimal subtotal = Items.Sum(x => x.Price);
if (subtotal > 100)
{
return subtotal * 0.80M;
}
else if (subtotal > 50)
{
return subtotal * 0.85M;
}
else if (subtotal > 10)
{
return subtotal * 0.90M;
}
else
{
return subtotal;
}
}
public decimal GenerateTotal()
{
decimal subtotal = Items.Sum(x => x.Price);
if (subtotal > 100)
{
return subtotal * 0.80M;
}
else if (subtotal > 50)
{
return subtotal * 0.85M;
}
else if (subtotal > 10)
{
return subtotal * 0.90M;
}
else
{
return subtotal;
}
}
Presentación de Func Delegate
Tim introduce el delegado func para resolver el problema de los descuentos codificados. El delegado func es un delegado genérico que representa una firma de método con un tipo de retorno y hasta 16 parámetros de entrada.
-
Definición del delegado Func:
- El delegado func se utiliza en el método GenerateTotal para gestionar los cálculos de descuento de forma dinámica.
public decimal GenerateTotal(Func<List<ProductModel>, decimal, decimal> calculateDiscountedTotal) { decimal subtotal = Items.Sum(x => x.Price); MentionDiscount(subtotal); return calculateDiscountedTotal(Items, subtotal); }public decimal GenerateTotal(Func<List<ProductModel>, decimal, decimal> calculateDiscountedTotal) { decimal subtotal = Items.Sum(x => x.Price); MentionDiscount(subtotal); return calculateDiscountedTotal(Items, subtotal); } -
Creación del método de cálculo de descuentos:
- En la clase Program se crea un método que coincide con la firma del delegado func.
private static decimal CalculateLevelDiscount(List<ProductModel> items, decimal subtotal) { if (subtotal > 100) { return subtotal * 0.80M; } else if (subtotal > 50) { return subtotal * 0.85M; } else if (subtotal > 10) { return subtotal * 0.90M; } else { return subtotal; } }private static decimal CalculateLevelDiscount(List<ProductModel> items, decimal subtotal) { if (subtotal > 100) { return subtotal * 0.80M; } else if (subtotal > 50) { return subtotal * 0.85M; } else if (subtotal > 10) { return subtotal * 0.90M; } else { return subtotal; } } -
Pasando el Método al Delegado Func:
- El método CalculateLevelDiscount se pasa al método GenerateTotal a través del delegado func.
class Program { static ShoppingCartModel cart = new ShoppingCartModel(); static void Main(string[] args) { PopulateCartWithDemoData(); Console.WriteLine($"The total for the cart is {cart.GenerateTotal(CalculateLevelDiscount):C2}"); Console.ReadLine(); } private static void PopulateCartWithDemoData() { cart.Items.Add(new ProductModel { ItemName = "Cereal", Price = 3.63M }); cart.Items.Add(new ProductModel { ItemName = "Milk", Price = 2.95M }); cart.Items.Add(new ProductModel { ItemName = "Strawberries", Price = 7.51M }); cart.Items.Add(new ProductModel { ItemName = "Blueberries", Price = 6.75M }); } private static decimal CalculateLevelDiscount(List<ProductModel> items, decimal subtotal) { if (subtotal > 100) { return subtotal * 0.80M; } else if (subtotal > 50) { return subtotal * 0.85M; } else if (subtotal > 10) { return subtotal * 0.90M; } else { return subtotal; } } }class Program { static ShoppingCartModel cart = new ShoppingCartModel(); static void Main(string[] args) { PopulateCartWithDemoData(); Console.WriteLine($"The total for the cart is {cart.GenerateTotal(CalculateLevelDiscount):C2}"); Console.ReadLine(); } private static void PopulateCartWithDemoData() { cart.Items.Add(new ProductModel { ItemName = "Cereal", Price = 3.63M }); cart.Items.Add(new ProductModel { ItemName = "Milk", Price = 2.95M }); cart.Items.Add(new ProductModel { ItemName = "Strawberries", Price = 7.51M }); cart.Items.Add(new ProductModel { ItemName = "Blueberries", Price = 6.75M }); } private static decimal CalculateLevelDiscount(List<ProductModel> items, decimal subtotal) { if (subtotal > 100) { return subtotal * 0.80M; } else if (subtotal > 50) { return subtotal * 0.85M; } else if (subtotal > 10) { return subtotal * 0.90M; } else { return subtotal; } } }
Ejecución de la aplicación
Tim demuestra la aplicación modificada, mostrando que funciona correctamente y calcula dinámicamente el descuento basándose en la lógica proporcionada.

Diferencias entre Delegate y Func
Tim compara el delegado personalizado y el delegado func:
-
Delegado: Requiere una definición explícita de la firma, proporcionando documentación y estructura claras.
- Func: Más conciso, pero requiere especificar los tipos de entrada y salida cada vez, lo que puede resultar menos claro.
Ambos enfoques ofrecen flexibilidad, pero la elección depende del caso de uso específico y de la complejidad de la aplicación.
¿Por qué usar delegados si todo el trabajo se hace en otra parte?
Tim Corey responde a una pregunta habitual sobre el uso de delegados: ¿Por qué tener un delegado si todo el trabajo parece estar hecho en otra parte?
Tim explica que el propósito de los delegados es proporcionar flexibilidad y extensibilidad en el código. El método GenerateTotal de la clase ShoppingCartModel puede hacer algo más que calcular descuentos. También puede encargarse de tareas como comprobar la disponibilidad de existencias, validar el contenido de los carritos u otras lógicas empresariales. Los delegados permiten pasar métodos específicos para tareas únicas o comportamientos personalizados sin cambiar el método principal. Esto hace que el código sea más modular y fácil de mantener.
Los delegados son especialmente útiles en situaciones en las que se desea:
- Aplicar diferentes reglas o lógicas de negocio de forma dinámica.
- El método principal debe ser genérico y reutilizable.
- Implementar comportamientos personalizados para casos específicos sin modificar el método central.
Action Delegate: Creación y explicación
Tim presenta el delegado de acción, otro tipo especial de delegado en C#. El delegado Action es similar a Func, pero no devuelve ningún valor (es decir, devuelve void).
-
Creación del delegado de acción:
- Defina el delegado Action en el método GenerateTotal para gestionar alertas o mensajes.
public decimal GenerateTotal(Func<List<ProductModel>, decimal, decimal> calculateDiscountedTotal, Action<string> tellUserWeAreDiscounting) { decimal subtotal = Items.Sum(x => x.Price); MentionSubtotal(subtotal); tellUserWeAreDiscounting("We are applying your discount."); return calculateDiscountedTotal(Items, subtotal); }public decimal GenerateTotal(Func<List<ProductModel>, decimal, decimal> calculateDiscountedTotal, Action<string> tellUserWeAreDiscounting) { decimal subtotal = Items.Sum(x => x.Price); MentionSubtotal(subtotal); tellUserWeAreDiscounting("We are applying your discount."); return calculateDiscountedTotal(Items, subtotal); } -
Creación del método de alerta:
- Defina un método que coincida con la firma del delegado de acción.
private static void AlertUser(string message) { Console.WriteLine(message); }private static void AlertUser(string message) { Console.WriteLine(message); } -
Pasar el método al delegado de acción:
- Pase el método AlertUser al método GenerateTotal a través del delegado Action.
class Program { static ShoppingCartModel cart = new ShoppingCartModel(); static void Main(string[] args) { PopulateCartWithDemoData(); Console.WriteLine($"The total for the cart is {cart.GenerateTotal(CalculateLevelDiscount, AlertUser):C2}"); Console.ReadLine(); } private static void PopulateCartWithDemoData() { cart.Items.Add(new ProductModel { ItemName = "Cereal", Price = 3.63M }); cart.Items.Add(new ProductModel { ItemName = "Milk", Price = 2.95M }); cart.Items.Add(new ProductModel { ItemName = "Strawberries", Price = 7.51M }); cart.Items.Add(new ProductModel { ItemName = "Blueberries", Price = 6.75M }); } private static decimal CalculateLevelDiscount(List<ProductModel> items, decimal subtotal) { if (subtotal > 100) { return subtotal * 0.80M; } else if (subtotal > 50) { return subtotal * 0.85M; } else if (subtotal > 10) { return subtotal * 0.90M; } else { return subtotal; } } private static void AlertUser(string message) { Console.WriteLine(message); } }class Program { static ShoppingCartModel cart = new ShoppingCartModel(); static void Main(string[] args) { PopulateCartWithDemoData(); Console.WriteLine($"The total for the cart is {cart.GenerateTotal(CalculateLevelDiscount, AlertUser):C2}"); Console.ReadLine(); } private static void PopulateCartWithDemoData() { cart.Items.Add(new ProductModel { ItemName = "Cereal", Price = 3.63M }); cart.Items.Add(new ProductModel { ItemName = "Milk", Price = 2.95M }); cart.Items.Add(new ProductModel { ItemName = "Strawberries", Price = 7.51M }); cart.Items.Add(new ProductModel { ItemName = "Blueberries", Price = 6.75M }); } private static decimal CalculateLevelDiscount(List<ProductModel> items, decimal subtotal) { if (subtotal > 100) { return subtotal * 0.80M; } else if (subtotal > 50) { return subtotal * 0.85M; } else if (subtotal > 10) { return subtotal * 0.90M; } else { return subtotal; } } private static void AlertUser(string message) { Console.WriteLine(message); } }
Creación de métodos anónimos: Delegado Anónimo
Tim muestra cómo utilizar métodos anónimos, lo que permite definir métodos sobre la marcha sin nombrarlos.
-
Definición de métodos anónimos:
- En lugar de crear métodos con nombre, puede definir los métodos directamente donde sean necesarios.
class Program { static ShoppingCartModel cart = new ShoppingCartModel(); static void Main(string[] args) { PopulateCartWithDemoData(); Console.WriteLine($"The total for the cart is {cart.GenerateTotal((items, subtotal) => { if (subtotal > 100) return subtotal * 0.80M; else if (subtotal > 50) return subtotal * 0.85M; else if (subtotal > 10) return subtotal * 0.90M; else return subtotal; }, (message) => Console.WriteLine(message)):C2}"); Console.ReadLine(); } private static void PopulateCartWithDemoData() { cart.Items.Add(new ProductModel { ItemName = "Cereal", Price = 3.63M }); cart.Items.Add(new ProductModel { ItemName = "Milk", Price = 2.95M }); cart.Items.Add(new ProductModel { ItemName = "Strawberries", Price = 7.51M }); cart.Items.Add(new ProductModel { ItemName = "Blueberries", Price = 6.75M }); } }class Program { static ShoppingCartModel cart = new ShoppingCartModel(); static void Main(string[] args) { PopulateCartWithDemoData(); Console.WriteLine($"The total for the cart is {cart.GenerateTotal((items, subtotal) => { if (subtotal > 100) return subtotal * 0.80M; else if (subtotal > 50) return subtotal * 0.85M; else if (subtotal > 10) return subtotal * 0.90M; else return subtotal; }, (message) => Console.WriteLine(message)):C2}"); Console.ReadLine(); } private static void PopulateCartWithDemoData() { cart.Items.Add(new ProductModel { ItemName = "Cereal", Price = 3.63M }); cart.Items.Add(new ProductModel { ItemName = "Milk", Price = 2.95M }); cart.Items.Add(new ProductModel { ItemName = "Strawberries", Price = 7.51M }); cart.Items.Add(new ProductModel { ItemName = "Blueberries", Price = 6.75M }); } } -
Comprensión de la sintaxis:
- La sintaxis del método anónimo utiliza el operador
=>(expresión lambda) para definir el cuerpo del método directamente en línea. - No es necesario especificar el tipo de retorno ni el nombre del método.
- La sintaxis del método anónimo utiliza el operador
Mediante el uso de delegados, incluidos Func, Action y métodos anónimos, los desarrolladores pueden crear código más dinámico y modular, lo que permite componentes flexibles y reutilizables.
Uso de delegados en otros proyectos: WinForms
En este segmento, Tim Corey demuestra el poder de los delegados extendiendo su uso a una aplicación WinForms. Se destaca cómo los delegados pueden facilitar diferentes comportamientos en diversos contextos de interfaz de usuario (UI).
Configuración de la aplicación WinForms
-
WinForm UI con dos botones:
-
El formulario tiene dos botones: uno para mostrar los cuadros de mensaje y otro para mostrar los cuadros de texto.
- También se incluye el modelo ShoppingCartModel y un método para rellenarlo con datos de demostración.
-
public partial class Dashboard : Form
{
ShoppingCartModel cart = new ShoppingCartModel();
public Dashboard()
{
InitializeComponent();
PopulateCartWithDemoData();
}
private void PopulateCartWithDemoData()
{
cart.Items.Add(new ProductModel { ItemName = "Cereal", Price = 3.63M });
cart.Items.Add(new ProductModel { ItemName = "Milk", Price = 2.95M });
cart.Items.Add(new ProductModel { ItemName = "Strawberries", Price = 7.51M });
cart.Items.Add(new ProductModel { ItemName = "Blueberries", Price = 6.75M });
}
private void messageBoxDemoButton_Click(object sender, EventArgs e)
{
decimal total = cart.GenerateTotal(SubtotalAlert, CalculateLevelDiscount, PrintOutDiscountAlert);
MessageBox.Show($"The total is {total:C2}");
}
private void textBoxDemoButton_Click(object sender, EventArgs e)
{
// Code for TextBox demo will go here
}
}
public partial class Dashboard : Form
{
ShoppingCartModel cart = new ShoppingCartModel();
public Dashboard()
{
InitializeComponent();
PopulateCartWithDemoData();
}
private void PopulateCartWithDemoData()
{
cart.Items.Add(new ProductModel { ItemName = "Cereal", Price = 3.63M });
cart.Items.Add(new ProductModel { ItemName = "Milk", Price = 2.95M });
cart.Items.Add(new ProductModel { ItemName = "Strawberries", Price = 7.51M });
cart.Items.Add(new ProductModel { ItemName = "Blueberries", Price = 6.75M });
}
private void messageBoxDemoButton_Click(object sender, EventArgs e)
{
decimal total = cart.GenerateTotal(SubtotalAlert, CalculateLevelDiscount, PrintOutDiscountAlert);
MessageBox.Show($"The total is {total:C2}");
}
private void textBoxDemoButton_Click(object sender, EventArgs e)
{
// Code for TextBox demo will go here
}
}
Creación de métodos para delegados
-
Alerta de descuento de impresión :
- Este método se utilizará para mostrar una alerta con la información del descuento.
private void PrintOutDiscountAlert(string message) { MessageBox.Show(message); }private void PrintOutDiscountAlert(string message) { MessageBox.Show(message); } -
SubtotalAlert :
- Este método mostrará el subtotal en un cuadro de mensaje.
private void SubtotalAlert(decimal subtotal) { MessageBox.Show($"The subtotal is {subtotal:C2}"); }private void SubtotalAlert(decimal subtotal) { MessageBox.Show($"The subtotal is {subtotal:C2}"); } -
CalcularDescuentoDeNivel:
- Este método calculará el descuento en función del número de artículos del carrito.
private decimal CalculateLevelDiscount(List<ProductModel> items, decimal subtotal) { if (items.Count > 3) { return subtotal - 3M; } return subtotal - items.Count; }private decimal CalculateLevelDiscount(List<ProductModel> items, decimal subtotal) { if (items.Count > 3) { return subtotal - 3M; } return subtotal - items.Count; }
Integración de los delegados con WinForms
-
Uso de delegados en eventos de clic de botón:
- El método
messageBoxDemoButton_Clickdemuestra cómo pasar los delegados al método GenerateTotal y manejar los resultados utilizando cuadros de mensaje.
private void messageBoxDemoButton_Click(object sender, EventArgs e) { decimal total = cart.GenerateTotal(SubtotalAlert, CalculateLevelDiscount, PrintOutDiscountAlert); MessageBox.Show($"The total is {total:C2}"); }private void messageBoxDemoButton_Click(object sender, EventArgs e) { decimal total = cart.GenerateTotal(SubtotalAlert, CalculateLevelDiscount, PrintOutDiscountAlert); MessageBox.Show($"The total is {total:C2}"); } - El método
-
Ejecución de la aplicación:
- Cuando se hace clic en el botón, la aplicación WinForms muestra el subtotal y el total mediante cuadros de mensaje, lo que demuestra la flexibilidad de los delegados.

Conclusión
Tim Corey explica los delegados en C# con claridad, cubriendo sus aspectos básicos, su uso avanzado y ejemplos prácticos como el uso de delegados en un carrito de la compra. Muestra cómo los delegados permiten un código flexible y reutilizable, incluyendo Func, Action y métodos anónimos. Vea el vídeo completo para aprender a aplicar delegados de forma eficaz en sus proyectos
