Earn More by Sharing What You Love
Do you create content for developers working with .NET, C#, Java, Python, or Node.js? Turn your expertise into extra income!

Tim Corey
1h 9m 11s
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.
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.
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; }
}Imports System
Imports System.Collections.Generic
Imports System.Linq
Namespace ConsoleUI
Class Program
Private Shared cart As New ShoppingCartModel()
Shared Sub Main(args As String())
PopulateCartWithDemoData()
Console.WriteLine($"The total for the cart is {cart.GenerateTotal():C2}")
Console.ReadLine()
End Sub
Private Shared Sub PopulateCartWithDemoData()
cart.Items.Add(New ProductModel With {.ItemName = "Cereal", .Price = 3.63D})
cart.Items.Add(New ProductModel With {.ItemName = "Milk", .Price = 2.95D})
cart.Items.Add(New ProductModel With {.ItemName = "Strawberries", .Price = 7.51D})
cart.Items.Add(New ProductModel With {.ItemName = "Blueberries", .Price = 6.75D})
End Sub
End Class
End Namespace
Public Class ShoppingCartModel
Public Property Items As List(Of ProductModel) = New List(Of ProductModel)()
Public Function GenerateTotal() As Decimal
Dim subtotal As Decimal = Items.Sum(Function(x) x.Price)
If subtotal > 100 Then
Return subtotal * 0.80D
ElseIf subtotal > 50 Then
Return subtotal * 0.85D
ElseIf subtotal > 10 Then
Return subtotal * 0.90D
Else
Return subtotal
End If
End Function
End Class
Public Class ProductModel
Public Property ItemName As String
Public Property Price As Decimal
End ClassTim 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.
Tim recorre la lógica del descuento en el método GenerateTotal, explicando cómo el subtotal determina el descuento aplicado:
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.
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.
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.
A continuación, Tim desglosa el proceso de creación y uso de un delegado:
Definir el delegado:
public delegate void MentionDiscount(decimal subtotal);Public Delegate Sub MentionDiscount(subtotal As Decimal)Uso del delegado en un método:
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:
private static void SubtotalAlert(decimal subtotal)
{
Console.WriteLine($"The subtotal is {subtotal:C2}");
}
Llamada al método GenerateTotal:
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 });
}
}
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.

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.
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 Function GenerateTotal() As Decimal
Dim subtotal As Decimal = Items.Sum(Function(x) x.Price)
If subtotal > 100 Then
Return subtotal * 0.80D
ElseIf subtotal > 50 Then
Return subtotal * 0.85D
ElseIf subtotal > 10 Then
Return subtotal * 0.90D
Else
Return subtotal
End If
End FunctionTim 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:
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:
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:
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;
}
}
}
Tim demuestra la aplicación modificada, mostrando que funciona correctamente y calcula dinámicamente el descuento basándose en la lógica proporcionada.

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.
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:
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:
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:
private static void AlertUser(string message)
{
Console.WriteLine(message);
}
Pasar el método al delegado de acción:
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);
}
}
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:
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:
=> (expresión lambda) para definir el cuerpo del método directamente en línea.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.
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).
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
Inherits Form
Private cart As New ShoppingCartModel()
Public Sub New()
InitializeComponent()
PopulateCartWithDemoData()
End Sub
Private Sub PopulateCartWithDemoData()
cart.Items.Add(New ProductModel With {.ItemName = "Cereal", .Price = 3.63D})
cart.Items.Add(New ProductModel With {.ItemName = "Milk", .Price = 2.95D})
cart.Items.Add(New ProductModel With {.ItemName = "Strawberries", .Price = 7.51D})
cart.Items.Add(New ProductModel With {.ItemName = "Blueberries", .Price = 6.75D})
End Sub
Private Sub messageBoxDemoButton_Click(sender As Object, e As EventArgs) Handles messageBoxDemoButton.Click
Dim total As Decimal = cart.GenerateTotal(AddressOf SubtotalAlert, AddressOf CalculateLevelDiscount, AddressOf PrintOutDiscountAlert)
MessageBox.Show($"The total is {total:C2}")
End Sub
Private Sub textBoxDemoButton_Click(sender As Object, e As EventArgs) Handles textBoxDemoButton.Click
' Code for TextBox demo will go here
End Sub
End ClassAlerta de descuento de impresión :
private void PrintOutDiscountAlert(string message)
{
MessageBox.Show(message);
}
SubtotalAlert :
private void SubtotalAlert(decimal subtotal)
{
MessageBox.Show($"The subtotal is {subtotal:C2}");
}
CalcularDescuentoDeNivel:
private decimal CalculateLevelDiscount(List<ProductModel> items, decimal subtotal)
{
if (items.Count > 3)
{
return subtotal - 3M;
}
return subtotal - items.Count;
}
Uso de delegados en eventos de clic de botón:
messageBoxDemoButton_Click demuestra cómo pasar los delegados al método GenerateTotal y manejar los resultados usando 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}");
}
Ejecución de la aplicació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
Do you create content for developers working with .NET, C#, Java, Python, or Node.js? Turn your expertise into extra income!
Join our newsletter, you’ll get exclusive access on article updates. We value your privacy