← C# EspañolChapter 12 of 13

Delegados, Eventos y Lambdas

## Objetivos de Aprendizaje - Comprender delegados - Trabajar con eventos - Dominar expresiones lambda - Aprender métodos anónimos ## Delegados ### ¿Qué es un Delegado? Un delegado es un tipo que representa referencias a métodos con una firma específica. ```csharp // Declaración de delegado delegate int Calculate(int a, int b); // Métodos que coinciden con la firma class MathOperations { public static int Add(int a, int b) => a + b; public static int Multiply(int a, int b) => a * b; } // Uso Calculate calc = MathOperations.Add; int result = calc(5, 3); // 8 calc = MathOperations.Multiply; result = calc(5, 3); // 15 ``` ### Delegados Genéricos (Incorporados) ```csharp // Func - devuelve un valor Func add = (a, b) => a + b; Func double = x => x * 2; Func getName = () => "Alice"; // Action - devuelve void Action print = Console.WriteLine; Action multiply = (a, b) => Console.WriteLine(a * b); // Predicate - devuelve bool Predicate isEven = x => x % 2 == 0; ``` ## Eventos ### Patrón Publicar-Suscribir ```csharp class Button { // Evento público public event EventHandler? Clicked; public void Click() { Console.WriteLine("Botón clickeado"); // Lanzar evento si hay suscriptores Clicked?.Invoke(this, EventArgs.Empty); } } // Suscriptor class Program { static void Main() { Button button = new Button(); // Suscribirse al evento button.Clicked += OnButtonClicked; button.Click(); } static void OnButtonClicked(object? sender, EventArgs e) { Console.WriteLine("¡El botón fue clickeado!"); } } ``` ### EventHandler ### Args de Evento Personalizado ```csharp class TemperatureEventArgs : EventArgs { public double Temperature { get; } public TemperatureEventArgs(double temp) => Temperature = temp; } class Thermometer { public event EventHandler? TemperatureChanged; public void Measure(double temp) { if (temp != lastTemp) { lastTemp = temp; TemperatureChanged?.Invoke(this, new TemperatureEventArgs(temp)); } } } // Uso Thermometer t = new Thermometer(); t.TemperatureChanged += (sender, e) => Console.WriteLine($"Temp: {e.Temperature}"); ``` ## Expresiones Lambda ### Sintaxis ```csharp // Sintaxis completa (int x, int y) => { return x + y; } // Cuerpo de expresión (sin return, sin llaves) x => x * 2; // Múltiples parámetros (a, b) => a + b; // Sin parámetros () => Console.WriteLine("Hola"); ``` ### Ejemplos ```csharp // Con Func Func square = x => x * x; Func concat = (a, b) => a + b; // Con Action Action print = msg => Console.WriteLine(msg); // Con Predicate Predicate isPositive = x => x > 0; // Lógica compleja Func grade = score => { if (score >= 90) return "A"; if (score >= 80) return "B"; return "C"; }; ``` ## Métodos Anónimos ### Antes de Lambdas ```csharp // Método anónimo delegate int Calculate(int a, int b); Calculate calc = delegate(int a, int b) { return a + b; }; // Con eventos button.Clicked += delegate(object? sender, EventArgs e) { Console.WriteLine("¡Clickeado!"); }; ``` ## Closures ### Capturar Variables ```csharp int multiplier = 10; Func multiply = x => x * multiplier; Console.WriteLine(multiply(5)); // 50 multiplier = 20; Console.WriteLine(multiply(5)); // 200 (¡captura por referencia!) ``` ### Error Común ```csharp var actions = new List(); // Incorrecto - todos capturan la misma variable for (int i = 0; i < 3; i++) { actions.Add(() => Console.WriteLine(i)); } foreach (var a in actions) a(); // Imprime: 3, 3, 3 // Correcto - capturar valor var actions2 = new List(); for (int i = 0; i < 3; i++) { int captured = i; // Capturar valor actions2.Add(() => Console.WriteLine(captured)); } foreach (var a in actions2) a(); // Imprime: 0, 1, 2 ``` ## Combinar Delegados (Multicast) ### Combinar Delegados ```csharp delegate void Notify(); Notify notify1 = () => Console.WriteLine("Manejador 1"); Notify notify2 = () => Console.WriteLine("Manejador 2"); Notify combined = notify1 + notify2; combined(); // Llama ambos Notify notify3 = () => Console.WriteLine("Manejador 3"); combined += notify3; combined(); // Llama los tres // Remover combined -= notify2; combined(); // Manejador 1 y 3 ``` ### Valores de Retorno con Multicast ```csharp delegate int Calculate(int x); Calculate calc = x => { Console.WriteLine($"Primero: {x}"); return x + 1; }; calc += x => { Console.WriteLine($"Segundo: {x}"); return x + 2; }; int result = calc(5); // ¡Solo el último valor de retorno se mantiene! // Salida: // Primero: 5 // Segundo: 5 // result = 7 ``` ## Patrones de Eventos Incorporados ### Firma Estándar de Evento ```csharp // Tipos de delegado estándar (ya definidos en .NET) public delegate void EventHandler(object? sender, EventArgs e); public delegate void EventHandler(object? sender, TEventArgs e); // Patrón común public event EventHandler? MyEvent; public event EventHandler? SpecializedEvent; ``` ## Covarianza y Contravarianza ### Con Delegados ```csharp // Covarianza - tipo de retorno puede ser más derivado delegate TextWriter WriterFactory(); WriterFactory factory = () => new StreamWriter("file.txt"); // Contravarianza - tipo de parámetro puede ser menos derivado Action writer = (StreamWriter sw) => sw.WriteLine("test"); Action textWriter = writer; // OK - TextWriter es base de StreamWriter ``` ## Resumen - Delegado: referencia a método tipo-seguro - Func: devuelve valor - Action: devuelve void - Predicate: devuelve bool - Evento: patrón publicador-suscriptor - Lambda: métodos anónimos concisos - Los closures capturan variables por referencia - Los delegados pueden combinarse (+, -) - Los eventos siguen el patrón estándar de .NET

Comments

Comments powered by Giscus

To enable comments, add your Giscus embed code here.

Learn more about Giscus →